在之前的任意一种顺序数据结构中,要查找某个元素时,都要进行遍历来查找。所以时间复杂度不可能为O(1)。如果有一种数据结构能不经过任何的比较就能直接得到要查找的元素,这种数据结构就是哈希表。
哈希表概念
在一种数据结构中,在插入元素时,由待插入元素的值根据一个特殊函数计算出该元素的存储位置,并将该元素放置在此处。在搜索元素时,还是由搜索的元素值根据这个特殊函数计算存储位置,直接在该位置将元素取出即可。
上述所说的特殊函数即为哈希函数,上述构造出来的结构称为哈希表(由数组实现)。
比如:一组数据:1 2 8 5 9。定义哈希函数是:hash(key) = key % m(m为内存单元个数,可以自己定义)。这里我们定义为10。
根据哈希函数计算存储位置:
hash(1) = 1;hash(2) = 2;hash(8) = 8;hash(5) = 5;hash(10) = 0
所以,这组数据存储如下:
如在查找2时,根据哈希函数得到存储位置为2,则此时直接在下标为2处进行查找,便可以不用比较就可以得到要查找的数据。
哈希冲突
如果在上述表中再插入一个元素12,发现根据哈希函数计算的下标也为2,而在下表为2处已经存放了数据。此时就发生了哈希冲突。
根据不同的关键字通过相同的哈希函数计算出相同的哈希地址,就称为发生了哈希冲突或哈希碰撞。
上述用到的哈希函数是除留余数法。
可以设计精妙的哈希函数来使产生哈希冲突的可能性尽可能的低,但不可能避免哈希冲突。
处理哈希冲突
闭散列:也叫开放地址法。当发生哈希冲突时,如果哈希表未被装满,说明哈希表中还有位置,此时就可以把key插入到下一个位置上。
可以使用线性探测来寻找下一个空余的位置。
线性探测:从发生冲突的位置开始,依次向后探测,直到找到空位置为止。
负载因子
当发生哈希冲突时,不同的关键码占据了可利用的空位置,使得寻找某关键码的位置需要进行多次比较,导致搜索效率降低。
当哈希表长一定时,填入表中的元素越多时,发生冲突的概率就越大,所以要控制插入表中的元素个数。因此引入负载因子。
哈希表的负载因子:a = 填入表中的元素个数/哈希表的长度。
所以当哈希表的负载因子达到一定的数值时,