哈希表及哈希冲突

目录

一. 哈希表的建立

1. 基本概念

2. 构建方法

二. 哈希冲突

1. 线性探测法

2. 分离链接法


引例题目(来源于PTA):

(1)线性探测法的查找函数

(2)分离链接法的删除操作函数

一. 哈希表的建立

1. 基本概念

哈希法又称散列法,即通过哈希函数来快速定位元素位置,用于存取元素,由此建立起来的存储表称为哈希表。

2. 构建方法

(1)数字分析法:取元素各位数字上分布较为均匀的数字位组合为存取地址。若各关键字中d4和d7的取值分布较均匀,则哈希函数为:h(key)=h(d1d2d3…d7d8)=d4d7;例如 h(81346532)=43,h(81301367)=06;

(2)平方取中法:数字不处理时数字分布不均匀,可以平方后再数字分析;

(3)分段叠加法:将数字分割为位数相等的几部分,重叠或者移位相加,和舍去高位结果为地址值;

(4)除留余数法:h(k) = k % p;

二. 哈希冲突

        哈希函数对于不同的元素可能计算出的地址是一样的,这就产生了哈希冲突,所以我们要处理哈希冲突。

1. 线性探测法

        线性探测法的思想是在冲突位置后面寻找不冲突的位置插入,查找时亦然。其实现代码如下:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef int ElemType;
typedef enum { Legitimate, Empty, Deleted } EntryType;
struct HashEntry{//节点
    ElemType Data;
    EntryType Info;
};
typedef HashEntry Cell;
struct TblNode{//哈希表
    int TableSize;//表长
    Cell *cells;//存储节点数组
};
typedef struct TblNode *HashTable;
int Hash(ElemType key,int sized){//哈希函数
     return key%sized;
}
int Find( HashTable H, ElemType key ){//查找函数(返回元素位置或者应该插入的位置)
    int pos = Hash(key,H->TableSize);
    for(int i = 0;i<H->TableSize;i++){
        int p = (pos + i)%H->TableSize;//!
        if(H->cells[p].Data==key||H->cells[p].Info==Empty)return p;
    }
    return -1;
}
void Insert(HashTable H,ElemType key){//插入函数
   int pos = Find(H,key);
   if(pos==-1){printf("Insert Error\n");return;}
   for(int i = 0;i<H->TableSize;i++){
        int p = (pos + i)%H->TableSize;
        if(H->cells[p].Info==Empty){
            H->cells[p].Data = key;
            H->cells[p].Info = Legitimate;
            return;
        }
   }
}
HashTable BuildTable(){//建立哈希表
    HashTable HB = (HashTable)malloc(sizeof(TblNode));
    scanf("%d",&HB->TableSize);
    HB->cells = (Cell*)malloc(sizeof(Cell)*HB->TableSize);
    for(int i = 0;i<HB->TableSize;i++)HB->cells[i].Info = Empty;//初始化
    for(int i = 0;i<HB->TableSize;i++){
        ElemType num;
        scanf("%d",&num);
        Insert(HB,num);//插入元素
    }
    return HB;
}
int main()
{
    HashTable H = BuildTable();
    for(int i = 0;i<H->TableSize;i++){
        if(i!=0)printf(" ");
        if(H->cells[i].Info==Empty||H->cells[i].Info==Deleted)printf("null");
        else printf("%d",H->cells[i].Data);
    }
    printf("\n");
    ElemType key;
    scanf("%d",&key);
    int pos = Find(H,key);
    if (pos==-1)
        printf("ERROR: %d is not found and the table is full.\n", key);
    else if (H->cells[pos].Info == Legitimate)
        printf("%d is at position %d.\n", key, pos);
    else
        printf("%d is not found.  Position %d is returned.\n", key, pos);

    return 0;
}

2. 分离链接法

        分离链接法又称为链地址法,其思想是把产生冲突的元素都放到一个集合里,查找时在集合中查找即可。其实现代码如下

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef int ElemType;
struct LNode{//节点
   ElemType Data;
   LNode *next;
};
typedef LNode *List;
struct TblNode{//哈希表
    int TableSize;//表长
    List Heads;//各地址集合的头节点
};
typedef TblNode *HashTable;
int Hash(ElemType key,int Size){//哈希函数
    return key%Size;
}
HashTable InitTable(){//初始化表
    HashTable HB = (HashTable)malloc(sizeof(TblNode));
    scanf("%d",&HB->TableSize);
    HB->Heads = (List)malloc(sizeof(LNode)*HB->TableSize);
    for(int i = 0;i<HB->TableSize;i++){
        HB->Heads[i].next = NULL;
    }
    return HB;
}
List Find(HashTable H,int key){//查找函数(返回位置指针/空指针)
   int pos = Hash(key,H->TableSize);
   List p = H->Heads[pos].next;
   while(p!=NULL){
       if(p->Data==key)return p;
       p = p->next;
   }
   return p;
}
void Insert(HashTable H,ElemType key){//插入函数
   List p = Find(H,key);
   if(p==NULL){//没有该元素
      int pos = Hash(key,H->TableSize);
      List L = (List)malloc(sizeof(LNode));
      L->Data = key;//头插法
      L->next = H->Heads[pos].next;
      H->Heads[pos].next = L;
   }
   else{//已存在
       printf("Insert Error! Exit\n");
   }
}
void BuildTable(HashTable H){//建立哈希表
    for(int i = 0;i<H->TableSize;i++){
        ElemType num;
        scanf("%d",&num);
        Insert(H,num);
    }
}
bool Delete( HashTable H, ElemType key ){//删除元素
    List p = Find(H,key);
    if(p==NULL)return false;
    else{
        int pos = Hash(key,H->TableSize);
        List L = &H->Heads[pos];
        while(L->next->Data!=key){
            L = L->next;
        }
        LNode *q = L->next;
        L->next = q->next;
        q->next = NULL;
        free(q);
        printf("%d is deleted from list Heads[%d]\n",key,pos);
    }
    return true;
}
int main()
{
    HashTable H = InitTable();
    BuildTable(H);
    ElemType Key;
    int T;
    scanf("%d",&T);
    while(T--){
         scanf("%d",&Key);
         if (Delete(H, Key) == false)
            printf("ERROR: %d is not found\n", Key);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿阿阿安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值