散列表处理冲突的方法


 选择一个“好”的散列函数可以在在一定程度上减少冲突,但在实际应用中很难完全避免冲突,所以选择一个有效的处理冲突的方法是非常重要的。创建散列表和查找散列表都会遇到冲突,这两种情况下处理冲突的方法应该是一致的。

创建散列表的方法和散列表本身的组织形式有关。按照组织形式的不同通常分位两大类:开放地址法和链地址法。

1.开放地址法

开放地址法的基本思想时:将记录都存储在散列表数组中,当某一记录关键字经过散列函数的计算所得到的初始地址H0此时已有其他关键字占据(即发生冲突),采取合适的方法计算得到另一个地址,如果仍然发生冲突,就以此地址为基础采取相同的计算方法,知道所得到的地址不再发生冲突。

这种方法在寻找下一个地址时,原来的数组空间对于所有的元素都是开放的,不管关键字key经过哈希函数计算所得到的初始地址是否与之相同,也没有其他的要求任何的元素中可以存储,所以称作开放地址法。

可用公式表示为

Hi=(H(key)+di)%m​   

其中H(key)表示哈希函数,m为散列表长度,di为增量序列。

根据di取值的不同可以分为以下两种情况

(1)线性探测法

di= 1,2,3,...,m-1

这种探测方法可以将散列表假象成一个循环表(实际并不是),发生冲突时,从冲突的下一单元顺序寻找空单元,如果最后一个位置都没有找到空单元,则回到表头继续查找,直到找到一个空位,就把此单元放入此空位。如果直到发生冲突的第一个单元(即经过哈希函数所得到的第一个初始地址)都没空位,则说明散列表已满,需要进行溢出处理

 

将一组关键字(9,1,23,14,55,20,84,27),采用散列函数:H(key)=key%7,表长为10,用线性探测法处理冲突

9%7=2    1%7=1    23%7=2(与9发生冲突)H=(H0+di)%(10-1)    di=1      14%7=0

55%7=6     20%7=6(与55发生冲突)H=(H0+di)%(10-1)  di=1

84%7=0(与14发生冲突) di=1,与1发生冲突 di=2,与9发生冲突 di=3,与23发生冲突 di=4,无冲突,所以di=4

27%7=6,与55,20发生冲突,所以di=2

(2)二次探测法

di=1^{2},-1^{2},2^{2},-2^{2},...+k^{2},-k^{2}​      k<=m/2(-1,-2的意思是可以向反方向探测)先右后左

将一组关键字(9,1,23,14,55,20,84,27),采用散列函数:H(key)=key%7,表长为10,用二次探测法处理冲突

 注意不是每次加di,而是从每加一次di都是从初始位置开始加的

2.链地址法

链地址法的基本思想是:将具有相同散列地址的记录放在同一个单链表中,称为同义词链表,不需要处理冲突。

以前面相同的题为例,采用尾插法,下面是示意图

 

 

以下是代码演示

线性探测法的代码实现

//开放地址法散列表的创建(从0开始)
void CreateHashTable(HashTable a[])
{
    int n;//存储数据个数
    cout<<"请输入数据的个数"<<endl;
    cin>>n;
    int c;//将地址存放于次
    int i;
    int key;//存放key
    int j;
    int h=0;//总的查找次数
    for(i=0;i<m;i++)//0-19存放数据
    {
        a[i].key=0;//赋初值
    }
    for(i=0;i<n;i++)
    {
        cout<<"请输入数据"<<endl;
        cin>>key;
        c=key%16;//哈希函数为key%16
        h++;
        if(a[c].key==0) {a[c].key=key;}//一次存储成功
        else
            for(j=c+1;;j++)//di可以改成不同的数
            {
                h++;
                if(a[j%m].key==0)
                    {a[j%m].key=key;
                    break;}
                if(j%m==c)
                {
                    cout<<"存储数据个数超过哈希表存储能力"<<endl;
                    break;
                }
            }

    }
    printf("ASL为%d/%d\n",h,n);

}

 链式探测法的代码实现

 1 void CreateHashTableNode(LNode* a[])
 2 {
 3     int n;
 4     int i;
 5     int c;
 6     LNode *p;
 7     cout<<"请输入关键数个数"<<endl;
 8     cin>>n;
 9    // LNode* a[m];
10     for(i=0;i<m;i++)//初始化
11     {
12         a[i]=new LNode;
13         a[i]->next=NULL;
14     }
15     int key;//存储key
16     cout<<"请输入关键字"<<endl;
17     for(i=0;i<n;i++)//n个关键字的存储
18     {
19         cin>>key;
20         c=key%16;//哈希函数
21         p=new LNode;
22         p->data=key;
23         p->next=a[c]->next;
24         a[c]->next=p;
25     }
26 
27 
28 }

 



免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM