ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

关于哈希

2022-05-31 12:00:26  阅读:121  来源: 互联网

标签:hash 哈希 int num 关于 key adj


今天老师讲了哈希,草草地整理一下:

哈希表,也称散列表,是一种高效的数据结构。它的最大优点就是把数据存储和查找所消耗的时间大大降低,几乎可以看成是 O(1)的,而代价是消耗比较多的内存。

他的基本实现原理就是将输入以某种方式转化为固定长度的输出,该输出就是散列值:

举个例子,比较两个字符串是否相同,可以将所有的字母转换为数字1到26,将字符串用数字累加求和再取余的方式求出散列值,通过比较两者散列值是否相等来判断两字符串是否相等

我们可以用前缀和的思想来计算每个字符串的哈希值:

 

通过这个例子我们就很好地解决了每个字符串的哈希值:

对于H(u,v)=l(v)-l(u)*10^?

 

这种方法固然很不错,但是也有一个小问题:两个不同的数据无法保证其散列值一定不同,也就会判断错误,这种情况叫做哈希冲突

那么如何解决这样的冲突呢???这里介绍两种方法:

1、拉链法(链地址法):

就是将具有相同哈希值的数据存在一个链表中,查找某一元素是否在哈希表时,就求出待判断的那个元素的散列值,并在哈希表中找到相应位置的地址,搜索这条链上的元素并判断是否相等即可,链表结构如下图所示:

  核心代码如下:

 1 //链地址法
 2 vector<int> hash_array[N];
 3 // hash_array:每个位置用一个 vector 来维护
 4 void push2(int x) 
 5 {
 6     int y = x % N; // 计算初始位置
 7     for(int i=0; i<hash_array[y].size(); i++)  if(hash_array[y][i] == x) // 如果之前已经出现过了
 8     {
 9         cout << x << "?has?occured?before!" << endl;  
10         return; // 标记已经出现过
11     }
12 // 如果之前没有出现过,将 x 加入表中
13     hash_array[y].push_back(x);
14     cout << x << "?inserted." << endl;
15 }

 

2.顺序询址法:

就是当有两个元素的散列值出现重复的时候,将后输入的元素往后放(如果后面有空的话),当然,如果后面也被占领了,就一直往后找,直到有空隙能够放下为止,

当想要查找一个元素时,先求出他的散列值,找到哈希表对应的位置,如果不是就一直往后找,如果查询到了当前位置为空时还没有找到此元素,那么这个元素就不存在,输出no,反之则输出yes

核心代码如下:

//顺序寻址法
int hash_table[N]; // hash_table 哈希表:0 位置代表没有数
void push1(int x)
{
    int y = x % N; // 计算初始位置,N:表的大小
    for(; hash_table[y]!=0 && hash_table[y]!=x; ) y = (y+1) % N;
// 寻找到一个 0 位置,或者找到自己为止
    if(hash_table[y]) cout << x << "?has?occured?before!" << endl;
// 如果是自己本身,则之前已经出现过了
    else
    {
        hash_table[y] = x; // 否则,将 x 加入表中
        cout << x << "?inserted." << endl;
    }
}

 

还有就是哈希表的常见构造方法,一种经典的叫做求模取余法(上文也有所体现):

尝试构造一种哈希函数:H(key)=key%p

其中p是一个可以自己拟定的值,但尽量要求p<=哈希表的表长m

哈希有很多的应用,比如:

输入n个整数,输入m为访问次数,每次访问是输入一个数并判断原序列中是否有这个元素

代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
const int N=50000; //定义总共输入哈希数字个数 
const int b=999979,H=999979;//哈希取模%数字 
int tot,adj[H],nxt[N],num[N];
int top,stk[N];
void init()
{ //初始化哈希表 
    tot=0;
    while(top)  //我们用一个栈存储下出现过的哈希值
       adj[stk[top--]]=0;
}    //每次把出现过的哈希值的链表清0,来节省时间

void insert(int key)
{  //将一个数字插入哈希表 
    int h=key%b; //除余法 
    for(int e=adj[h];e;e=nxt[e])
       if(num[e]==key) //诺链表中已存在当前数字则不再存 
          return;
    if(!adj[h]) stk[++top]=h; //把第1次出现的哈希值入栈
    nxt[++tot]=adj[h],adj[h]=tot; //建立链接 
    num[tot]=key; //建立链接表,存储值等于key的数字。 
}
 
bool query(int key)
{
    int h=key%b;
    for(int e=adj[h];e;e=nxt[e]) //查询链接 
       if(num[e]==key) return true;
    return false;  
 } 
 
int main()
{ 
    int a[10000];
    init();
    int n,m;
    cin>>n;
    for(int i=1;i<=n;++i) 
    {
        cin>>a[i];
        insert(a[i]);
    }
    cin>>m;
    int num;
    for(int i=1;i<=m;++i)
    {
        cin>>num;
        if(query(num))
            printf("yes\n");
        else
            printf("no\n");
    }
}

 

标签:hash,哈希,int,num,关于,key,adj
来源: https://www.cnblogs.com/zch061023/p/16329889.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有