解决散列表冲突问题-开放定址法

指针是我们学习C语言的一大瓶颈,用分离链接散列算法的一大缺点也是因为他用到了指针,涉及到了内存分配。开放定址散列法是另一种解决冲突而不需要用到指针的算法。

开放地址散列法的基本思想是,遇到了冲突,我们就用另一套法则,将此关键字放在其他的空缺位置上。显而易见,他的缺点是散列表的创建必须足够大,才能够容许我们进行相关的操作,比起分离链接法来讲,虽然算法速度上有所提升,但是内存浪费比较大。因为他的装填因子λ应该低于0.5

装填因子:散列表的装填因子(load factor)λ为散列表中的元素个数与散列表大小的比值。

1.线性探测法

在原来的散列表基础之上添加增量序列,(1,2……,TableSize-1)循环试探下一个存储地址。

解决散列表冲突问题-开放定址法_第1张图片

只要表足够大,我们就能根据这个方法找到相应的位置,但是这样花费的时间更多,且浪费了很多空间,这样占据的单元也会开始形成一些区块,这样的结果称为一次聚集

2.平方探测 – 二次探测

平方探测法:以增量序列1²,-1²,2²,-2²,……,q²,-q² 且 q≤|TableSize/2|玄幻试探下一个存储地址

伪代码描述

类型声明

struct HashEntry
{
    ElementType Element;
    enum KindOfEntry Info;
};

typedef struct HashEntry Cell;

struct HashTbl
{
    int TableSize;
    Cell *TheCells;
}

初始化开放定址散列表

HashTable
InitializeTable(int TableSize)
{
    HashTable H;
    int i;
    if(TableSize < MinTableSize)
    {
        Error("Table size too small");
        return NULL;
    }
    /*Allocate table*/
    H = malloc( sizeof(struct HashTbl));
    if(H == NULL)
        FatalError("Out of space!!");
    H->TableSize = NextPrime(TableSize);
    /*Allocate array of cells*/
    H->TheCells = malloc( sizeof(cell) * H->TableSize);
    if(H->TheCells == NULL)
        FatalError(" Out of space !!");
    for(i = 0; i < H->TableSize; i++)
        H->TheCells[i].Info = Empty;
    return H;
}

看得出来开放定址的初始化和分离链接的初始化大致相同。

Find例程

Position
Find(ElementType key, HashTable H)
{
    Position CurrentPos;
    int CollisionNum;
    CollisionNum = 0;
    CurrentPos = Hash(key, H->TableSize);
    while(H->TheCells[ CurrentPos].Info !=Empty &&
            H->TheCells[ CurrentPos].Element != key)
            /*Probably need strcmp*/
    {
        CurrentPos += 2 * ++CollisionNum -1;
        if(CurrentPos >= H->TableSize)
            CurrentPos -= H->TableSize;
    }
    return CurrentPos;     //return the position

虽然说平方探测派出了一次聚集,但是散列到同一位置上的那些元素将探测相同的备选单元。形成了二次聚集。

你可能感兴趣的:(数据结构与算法)