• 哈希表


    一.符号表问题

    1.一个表里面放着n条记录,(记录x:x通常是一个指向实际数据的指针)

    2.在每个记录中,存在一个记录的键,还存在一些卫星数据(属于键的附加数据)

    3.排序是对记录进行排序,而不是关键字

    4.对表进行操作:添加记录,删除记录,查找具有特定键的记录

    二.直接映射表(数组)

    1.适用于关键字的全域(可能存储的关键字)较小的情况

    2.数组的每个位置对应全域中的一个关键字,关键字k的元素被存放在槽k中  

    3.缺陷:如果关键字只有几千,而关键字的全域需64位来表示,导致大量空槽

     1 class direct_address_table:
     2     '''直接寻址表'''
     3     def __init__(self, T=[], size=0):
     4         if len(T) == 0:
     5             self.T = [None for i in range(size)]
     6         else:
     7             self.T = T
     8         self.size = size
     9     '''对于节点'''
    10     def search(self, k):
    11         return self.T[k]
    12 
    13     def insert(self, x):
    14         self.T[x.key] = x
    15 
    16     def delete(self, x):
    17         self.T[x.key] = None
    18 
    19 class Node:
    20     def __init__(self, key):
    21         self.key = key
    22 
    23 T=[]
    24 dat=direct_address_table(T,10)
    25 x=Node(2)
    26 print(dat.insert(x))
    直接寻址表

    三.哈希表(散列表)(Hash Table)(一个长度与实际存储关键字数目成比例的数组)

    1.哈希法:用一个hash函数来随机映射那些键到哈希表T的槽

    2.哈希表是一种根据关键字,计算相应的存储位置,访问数据的数据结构,

    3.适用于:实际存储的关键字数目比全部的可能关键字总数较少时

    4.利用哈希函数(hash function)h,把原来具有关键字k的元素存放在槽k中变成该元素放在h(k)中

    三.哈希函数

    一个好的哈希函数:每个关键字都被等可能地哈希到m个槽位中的任何一个,并与其他关键字已散列到哪个槽位无关

    (1)除法散列法:用一个特定的素数m来除所给的关键字,h(k)=k mod m ,k为关键字,m为散列表大小而且不能太小,m一般不为2的幂或10的幂等相似的

    (2)乘法散列法:对m的选择不是特别关键,一般为2的幂,A不要太接近以2为底的数

    (3)全域散列法:从一组精心设计的函数中,随机地选择一个作为散列函数,使之独立于要存储的关键字

    三.冲突:多个关键字映射到数组的同一下标

     解决冲突:

    (1)链接法:把相同的哈希值的记录放到一个链表里存储

    最坏情况分析:所有键映射到同一个槽,访问θ(n)

    平均情况分析:假设简单均匀哈希(每个属于集合的键都有相同的几率被哈希映射到表的任意一个槽中),每个键与其他的键相互独立

     

    1是把键只哈希映射到槽所需要的时间,α是搜索槽对应的链表所花费的时间

     1 class chained_hash:
     2     '''链接法散列,查找和插入时都要判断槽中有没有元素'''
     3     def __init__(self, T=[], size=0):
     4         if len(T) == 0:
     5             self.T = [None for i in range(size)]
     6         else:
     7             self.T = T
     8         self.size = size
     9     def search(self, k):
    10         if self.T[self.hash_h(k)] != None:
    11             x = self.T[self.hash_h(k)].list_search(k)
    12             return x
    13         return None
    14     def insert(self, x):
    15         if self.T[self.hash_h(x.key)] == None:
    16             self.T[self.hash_h(x.key)] = DoublyLinkedList(x)
    17         else:
    18             self.T[self.hash_h(x.key)].list_insert(x)
    19     def delete(self, x):
    20         self.T[self.hash_h(x.key)].list_delete(x)
    21     def hash_h(self, key):
    22         '''hash函数'''
    23         return key % 12
    24 
    25 class Node:
    26     def __init__(self, key):
    27         self.key = key
    28 class DoublyNode:
    29     def __init__(self, n_prev, n_next, key):
    30         self.prev = n_prev
    31         self.next = n_next
    32         self.key = key
    33 
    34 class DoublyLinkedList:
    35     def __init__(self, head):
    36         self.head = head
    37 
    38     def list_search(self, k):
    39         x = self.head
    40         while x != None and x.key != k:
    41             x = x.next
    42         return x
    43 
    44     def list_insert(self, x):
    45         x.next = self.head
    46         if self.head != None:
    47             self.head.prev = x
    48         self.head = x
    49         x.prev = None
    50 
    51     def list_delete(self, x):
    52         if x.prev != None:
    53             x.prev.next = x.next
    54         else:
    55             self.head = x.next
    56         if x.next != None:
    57             x.next.prev = x.prev
    58 
    59 T=[]
    60 x=DoublyNode(None,None,13)
    61 ch=chained_hash(T,12)
    62 ch.insert(x)
    63 x=DoublyNode(None,None,25)
    64 ch.insert(x)
    65 y=ch.search(25)
    66 print(y.key)
    67 
    68 ch.delete(y)
    69 print(ch.T[1].head)
    70 print(ch.T[1].head.key)
    71 print(ch.T[1].head.next)
    72 -----------------------------------------
    73 25
    74 <__main__.DoublyNode object at 0x039C78B0>
    75 13
    76 None
    链接法散列

    (2)开放寻址法:所有元素都存放在散列表中,系统地探查哈希表直到找到空槽

    探查:连续地检查散列表,来找到空槽放置待插入的关键字

    计算开放寻址中的探查序列:

    (1)线性探查:h(k,i)=(h'(k)+i)mod m ,i=1...m-1

    (2)二次探查:h(k,i)=(h'(k)+c1 i+c2 i*2)mod m, 

    (3)双重散列:(h1(k)+ih2(k))mod m 

     1 class open_address_hash:
     2     '''开放寻址散列,散列表T和一个关键字k'''
     3     def __init__(self, T=[], size=0):
     4         if len(T) == 0:
     5             self.T = [None for i in range(size)]
     6         else:
     7             self.T = T
     8         self.size = size
     9 
    10     def hash_insert(self, k):
    11         '''插入关键字k,返回k的插槽或已满标志'''
    12         i = 0
    13         while i < self.size:
    14             j = self.hash_h1_h2(k, i)#搜寻空槽并插入
    15             if self.T[j] == None:
    16                 self.T[j] = k
    17                 return j
    18             else:
    19                 i += 1
    20         return "hash table overflow"
    21 
    22     def hash_search(self, k):
    23         '''查找,如果槽j包含了关键字k,则返回j,否则返回NOne'''
    24         i = 0
    25         j = self.hash_h1_h2(k, i)
    26         while self.T[j] != None and i < self.size:
    27             j = self.hash_h1_h2(k, i)
    28             if self.T[j] == k:
    29                 return j
    30             else:
    31                 i += 1
    32         return None
    33 
    34     def hash_h1_h2(self, k, i):
    35         '''hash 函数'''
    36         return ((k % self.size + i * (1 + k % (self.size - 2)))) % self.size
    37 
    38 T=[]
    39 oah=open_address_hash(T,13)
    40 print(oah.hash_insert(79))
    41 print(oah.hash_insert(69))
    42 print(oah.hash_search(50))
    43 ------------------------------
    44 1
    45 4
    46 None
    开放地址散列

    四.全域哈希和完全哈希

    1.哈希的根本缺陷:对任意哈希函数,都存在一个不好的键集,所有键都会哈希映射到同一个槽

    2.全域哈希:随机选择哈希函数,使之独立于要存储的关键字

  • 相关阅读:
    BZOJ3196: Tyvj 1730 二逼平衡树
    (转载)你真的会二分查找吗?
    Codeforces Round #259 (Div. 2)
    BZOJ1452: [JSOI2009]Count
    BZOJ2733: [HNOI2012]永无乡
    BZOJ1103: [POI2007]大都市meg
    BZOJ2761: [JLOI2011]不重复数字
    BZOJ1305: [CQOI2009]dance跳舞
    挖坑#4-----倍增
    BZOJ1042: [HAOI2008]硬币购物
  • 原文地址:https://www.cnblogs.com/yu-liang/p/9226447.html
Copyright © 2020-2023  润新知