最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

当前头条:[数据结构] 哈希表 (开放寻址法+拉链法)

来源:博客园


(资料图)

哈希表

哈希表的基本概念

哈希表Hash table是一种提供快速查找和插入元素的数据结构,也称散列表。哈希表是基于数组的扩展,一般利用数组的下标作为哈希表的键值。

哈希表存储的是由键(key)和值(value)组成的数据。键值 key是由哈希函数得到的。

哈希函数

除留余数法

除留余数法是一种广泛运用的哈希函数,其用插入元素 mod哈希表长度来得到关键字。由于哈希表是基于数组的,假如要插入负数元素,在C、C++中取模后还是负数,但是数组的下标不可以为负,所以哈希函数写成下列形式:

其中 x为插入元素, N为哈希表长度。这样取模后,得到的是非负数。

除留余数法函数

int Hash(int x){    return ((x % N) + N) % N;}

处理哈希冲突

哈希表中每个键值很可能对应了多个元素,所以哈希冲突不可避免,常用解决哈希冲突的方法有两种,分别为 开放地址法拉链法

开放寻址法

开放寻址法即当元素不能直接存放在哈希函数计算出来的数组下标时,就需要寻找其他位置来存放。我们一般采用线性探测,当对应键位置 k已经存在元素时,则将 k进行加一,探测下一个位置是否为空。但这样的处理冲突方法比较低效。

开放寻址法代码

#include#includeusing namespace std;static const int N = 14, inf = 0x3f3f3f3f;int h[N];void init(){    memset(h, 0x3f, sizeof(h));}int Hash(int x){    return ((x % N) + N) % N;}bool find(int x){    int k = Hash(x);    if(h[k] == inf) return false; //当前键值对应为空    while(h[k] != x){        k = (k + 1) % N;        if(h[k] == inf || k == Hash(x))            return false;         //回到起点    }    return true;}void insert(int x){    int k = Hash(x);    while(h[k] != inf) k = (k + 1) % N;    h[k] = x;}int main(){    init();    for(int i = 9; i <= 15; i++)        insert(i);    for(int i = 7; i <= 13; i++)        if(find(i))            cout<<"YES"<

拉链法

拉链法是比较常用的处理哈希冲突的方法。我们使用一个数组,数组的每个位置存放一个链表,这样当对应键存在多个元素需要存放时,可以很方便地将元素插入到对应链表中。

拉链法使用的结构和图的领接表很像,后续也称之为邻接表吧。

拉链法 邻接表

#include#includeusing namespace std;static const int N = 7;typedef struct node{    int val;    node *next;}node;node* h[N];       //邻接表void init(){    for(int i = 0; i < N; i++){        h[i] = new node;        h[i]->val = -1;        h[i]->next = NULL;    }}int Hash(int x){    return ((x % N) + N) % N;}bool find(int x){    int k = Hash(x);    for(node* p = h[k]->next; p; p = p->next)        if(p->val == x)            return true;    return false;}void insert(int x){    int k = Hash(x);    node* cur = new node;    cur->val = x;    cur->next = h[k]->next;    //头插法    h[k]->next = cur;}int main(){    init();    for(int i = 1; i <= 17; i++)        insert(i);    for(int i = 15; i <= 20; i++)        if(find(i))            cout<<"YES"<next;        cout<<"key = "<val<<" ";            t = t->next;        }        cout<

拉链法 vector邻接表

相关试题 Acwing 840.模拟散列表也可以用 vector来实现邻接表。

#include#includeusing namespace std;const int N = 100003;vector h[N];void insert(int x){    int k = (x % N + N) % N;  //余数可能为负数    h[k].push_back(x);}bool find(int x){    int k = (x % N + N) % N;    for(auto &cur : h[k])        if(cur == x)            return true;    return false;}int main(){    cin.tie(0); cout.tie(0);    int n;  cin>>n;    while(n--){        char op;        int x;        cin>>op>>x;                if(op == "I")            insert(x);        else{            if(find(x))                puts("Yes");            else                puts("No");        }    }}

拉链法 链式前向星

用链式前向星相比 vector容器更快,这种链式结构在竞赛中用得比较多。

#include#includeusing namespace std;const int N = 100003;int Hash[N], e[N], ne[N], idx;void insert(int x){    int k = (x % N + N) % N;  //余数可能为负数    e[idx] = x;    ne[idx] = Hash[k];    Hash[k] = idx++;}bool find(int x){    int k = (x % N + N) % N;    for(int i = Hash[k]; i != -1; i = ne[i])        if(e[i] == x)            return true;    return false;}int main(){    cin.tie(0); cout.tie(0);    int n;  cin>>n;        memset(Hash, -1, sizeof(Hash));    while(n--){        char op;        int x;        cin>>op>>x;                if(op == "I")            insert(x);        else{            if(find(x))                puts("Yes");            else                puts("No");        }    }}

关键词: 数据结构 基本概念 不可避免