散列(哈希)实现以及如何解决散列冲突

近来上班划水划得起飞,又有时间可以写文章了。

  先总结一下《数据结构与算法分析》中散列的定义:

散列函数:每个关键字被映射到从0到Tablesize -1这个范围中的某个数,并且被放到适当的单元中。这个映射关系被称为散列函数。

散列冲突(哈希冲突):两个关键字散列到同一个值。

 

哈希代码:

第一种(适用整数):

typedef unsigned int Index;

Index Hash(const char *key, int tableSize)
{
    unsigned int hashVal = 0;
    while (*key != '\0')
    {
        hashVal += *key++;
    }
    
    return hashVal % tableSize;
}

 

第二种(适用字符串): 空间利用率极低。

假设Key至少有两个字符外加NULL结尾的字符串。

26个字母+空格=27。 从最高位到最低位分别乘以27的平方、27的一次方和27的0次方。相当于该字符串为27进制的数。

3个字符(忽略空格)有26^3种组合,实际上3个字母组成的单词只有2851种。

最多只能用到表的28%的空间, 空间利用率极低。

Index Hash(const char *key, int tableSize)
{
    return (key[0] + 27 * key[1] + 729 * key[2]) % tablesize;
}

 

第三种(适用字符串):

Index Hash(cosnt char *key, int tableSize)
{
    unsigned int hashVal = 0;
    
    while(*key)
    {
        hashVal = (hashVal << 5) + *key++; //向左移动5位比乘以27的运算速度快。
    }
}

 

解决冲突的方式:

  • 分离链接法

将散列到同一个值的所有元素保留到一张表。例如10和20, 采用相同的散列函数Hash(X) = X mod 10。 那么10和20经过散列后得到同一个值,那么在Key[X}中,能找到10和20。

通常在某位置以遍历方式查找某元素。

#pragma once

struct ListNode;
typedef struct ListNode *Position;
struct HashTbl;
typedef struct HashTbl *HashTable;

HashTable InitializeTable(int tableSize);
void DestroyTable(HashTable h);
Position Find(ElementType key, HashTable h)
void Insert(ElementType key, HashTable h);
ElementType Retrieve(Position p);

sturct ListNode 
{
    ElementType Element; //当前元素值
    Position Next;       //下一节点
};

typedef Position List;

struct HashTbl
{
    int tableSize;
    List *TheLists;  //二级指针,指向 指向ListNode结构的指针的指针。
};

 

HashTable InitializeTable(int tableSize)
{
    HashTable H;
    int i;
    
    if(tableSize < minTableSize)
    {
        Error("Table size too small");
        return nullptr;
    }
    
    h = malloc(sizeof(struct HashTbl));
    
    if(H == nullptr)
    {
        FatalError("Out of space!!!")
    }
    
    H->TableSize = NextPrime(tableSize); //设置表的大小为素数
    
    /* Allocate array of lists */
    H->TheLists = malloc(sizeof(List) * H->tableSize); //指针数组
    if(H->TheLists == nullptr)
    {
        FatalError("Out of space");
    }
    
    /*Allocate list headers
     *设置链表头*/
    
    for(i = 0; i < H->tableSize; ++i)
    {
        H->TheLists[i] = malloc(sizeof(struct ListNode));
        if (H->TheLists[i] == nullptr)
        {
            FatalError("Out of space!!!");
        }
        else
        {
            H->TheLists[i]->Next = nullptr;
        }
    }
    
    return H;
}

 

Position Find(ElementType key, HashTable H)
{
    Position P;
    List L;
    
    L = H->TheLists[Hash(key, H->tableSize)];
    P = L->Next;
    
    /*遍历链表*/
    while(P && P->Element != key)
    {
        P = P->Next;
    }
    return P;
    
}

 

 

  • 开放定址法
  1. 线性探测法
  2. 平方探测法
  3. 双散列
  • 再散列

 

 

 

  1.  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值