数据结构-散列

散列表也叫散列,是以常数平均时间进行插入,查找,删除。散列的作用是将数据均匀的分布在不同的数据域中。根据散列值,将数据映射到对应的数据单元中,查找时根据散列值,直接在该数据单元中查找。将数据映射到不同数据域的函数叫做散列函数。具有一个好的散列函数和一个适合的散列表的大小能够将数据均匀的分布在散列表上。

一个较好的散列函数
public static int hash(String key, int tableSize){
        int hashValue = 0;
        for(int i = 0; i < key.length(); i++){
            hashValue = 37*hashValue + key.charAt(i);
        }
        hashValue %= tableSize;
        if(hashValue < 0){
            hashValue += tableSize;
        }
        return hashValue;
    }

接下来要解决的就是冲突问题。那么多的数据肯定有数据的散列值是一样的,所以我们需要解决冲突。
①分离链表法:
就是将散列值一样的保存到一个链表中,整个哈希表相当于一个链表数组。

除此之外还有不用链表的散列表,解决冲突的方式就是尝试另外的单元,直到直到空的单元为止。
②线性探测法
当发生冲突时,逐个探索空单元(可绕回),发现空单元就插入。
数据结构-散列_第1张图片
当插入49时,发现和89冲突,则向下逐个探测,绕回到0,发现空,就插入。但是这样插入的单元会形成区块,当查找时会探测好几次才能找到。
③平方探测法
采用f(i)=i^2的探测顺序,逐个探测距离为1,4,9。。。i^2的位置。但是我们发现当表的大小不是素数时,在表被填充一半之前就不能找到新的空单元了。那么我们需要知道有个定理:如果用平方探测法,且表的大小是素数,那么当表至少有一半是空的时候,总能插入一个新元素。

在探测散列表中删除操作不能执行,因为响应的单元已经引起过冲突,元素绕过了它存在了别处,所以我们需要懒惰删除。
④双散列
平方探测虽然避免了一次聚集,但是散列到同一个位置的元素将探测相同的备选单元,这叫二次聚集。双散列则可以弥补这个遗憾。
双散列的探测函数为f(i)=i*hash2(x) 意思为如果产生冲突,将第二个散列函数应用到x,然后再hash2(x),2*hash2(x)…..的距离进行探测。
⑤再散列
当散列表的元素过于满时,增加表的大小,扫描原表的所有元素,将元素重新散列到新表中。

你可能感兴趣的:(数据结构,数据结构,散列函数)