📜  散列中的二次探查(1)

📅  最后修改于: 2023-12-03 15:10:16.839000             🧑  作者: Mango

散列中的二次探查

简介

在散列表中,散列函数将键映射到散列表中的桶数组的索引位置。对于任何一个特定的键,理论上可能会出现多个键映射到相同的索引位置,这就是散列冲突。散列冲突解决的一种方法是在发生冲突时,将键插入到索引位置的链表或树中。但散列冲突的数量可能会导致链表或树过于庞大,这就导致了查找的效率降低。二次探查则是散列函数发生冲突时,重新计算新的索引位置,在该位置上查找是否可用,如可用则插入,否则重复该过程。

二次探查方法

二次探查的核心方法是重新计算新的索引位置。具体实现是通过计算探查的步骤,例如第一次探查的位置是散列函数直接计算得到的索引位置,在第一次探查被占据的情况下,第二次探查的位置为原位置加上一个偏移量的平方,即 hash(key) + (probe * probe),其中 probe 是探查步骤,成功找到空位置则将键插入该位置,否则继续二次探查直到成功为止。

二次探查的优点与缺点

与链表解决散列冲突的方法相比,二次探查的优点是可以避免链表过长而导致性能下降。此外,实现起来简单,需要的空间较少。但是,二次探查也存在缺点,例如表的负载因子应该控制在0.5以下,否则插入的时间将变得很慢。此外,当探查步骤较小时,可能会导致二次探查效率低下。

代码示例

下面是使用Python实现的二次探查散列表例子:

class HashTable:
    def __init__(self):
        self.capacity = 10 # 初始桶数组长度为10
        self.size = 0 # 当前存储的键值对数
        self.table = [None] * self.capacity

    def hash(self, key):
        # 散列函数,返回键对应的索引位置
        return hash(key) % self.capacity

    def rehash(self, old_hash, probe):
        # 计算二次探查的新索引位置
        return (old_hash + (probe * probe)) % self.capacity

    def put(self, key, value):
        if self.size >= self.capacity * 0.5:
            # 如果负载因子达到0.5,则增加桶数组的长度
            self.capacity *= 2
            new_table = [None] * self.capacity
            for i in range(len(self.table)):
                if self.table[i] is not None:
                    new_hash = self.hash(self.table[i][0])
                    for j in range(1, self.capacity):
                        new_index = self.rehash(new_hash, j)
                        if new_table[new_index] is None:
                            new_table[new_index] = (self.table[i][0], self.table[i][1])
                            break
                        elif new_table[new_index][0] == self.table[i][0]:
                            new_table[new_index] = (self.table[i][0], value)
                            break
            self.table = new_table

        hash_key = self.hash(key)
        for i in range(1, self.capacity):
            index = self.rehash(hash_key, i)
            if self.table[index] is None:
                self.table[index] = (key, value)
                self.size += 1
                return
            elif self.table[index][0] == key:
                self.table[index] = (key, value)
                return


    def get(self, key):
        hash_key = self.hash(key)
        for i in range(1, self.capacity):
            index = self.rehash(hash_key, i)
            if self.table[index] is None:
                return None
            elif self.table[index][0] == key:
                return self.table[index][1]

    def delete(self, key):
        hash_key = self.hash(key)
        for i in range(1, self.capacity):
            index = self.rehash(hash_key, i)
            if self.table[index] is None:
                return
            elif self.table[index][0] == key:
                self.table[index] = None
                self.size -= 1
                return