数据结构 哈希表

这是一类用于查找到数据结构

哈希函数

我们先来想一下,在用数组储存时,如果我们知道下标我们是不是直接就可以查找到这个数据,即时间复杂度是O(1).

假设有一个整型数组,我们将数字m映射到n处,如果我们想查找m是不是在数组中,我们可以将m映射成为n,去下标位n的地方查找。这个映射方法就是一个哈希函数,推广就是把一个任意类型的元素(即在任意类型的数组中)映射成一个只能为整型的下标。

举个例子:

14

                           0        1        2       3        4       5        6      7      8      9     

设这个哈希函数是一个值对数组长度的运算法则。设值为14,那么它就存在下标为14%9=5处.但是假设我们还想存储一个数字为5,我们会发现存不下了,那么思考一下,数字5应该怎么存储?

这个时候我们来介绍冲突处理方法,以处理这种问题。

冲突处理

其实冲突处理方法一种是拉链法,一种是开放定址法。

最容易理解的方法,就是往后找,如果5映射到数组上下标应该是5,而下标是5 的地方已经有数据了,那我们判断下标为6的地方是否有数据,如果没有就把5放到下标为6处,否则继续判断下一位。

145

                           0        1        2       3        4       5        6      7      8      9     

在开放定址法里面会有线性探测法,即我们刚刚说的方法,还有就是平方探测法,以刚刚的例子就是如果下标为5处有数据,但是我们五按照我们的哈希函数法则应该储存于下表为5处,我们就把应该存入的下标+1^2=+1即6处,如果下标为6处有数据,我们就进行一个-1^2=-1的操作即存入下标为4处,如果没有数据就存入如果没有进行相似操作+2^2,-2^2,+3^2,-3^2……

代码实现

对于代码演示我们用拉链法解决冲突

代码如下:

#include<bits/stdc++.h>
#include<stdlib.h>
#include<string.h>
//最重要两部分是冲突处理方法和哈希函数 
using namespace std;
typedef long long ll;
typedef struct Node{
	char *str;//假设哈希我们要存入字符串 
	struct Node *next;//拉链法 ,下一个节点 
}Node;
typedef struct HashTable{
	Node**data;//存储若干链表头地址的数组 
	//链表头地址是Node*
	int size;//哈希表大小 
	
}HashTable;
//int Ha
Node *init_node(char*str,Node*head){//使用链表的头插法 
	Node *p=(Node*)malloc(sizeof(Node));
	//Node*p;
	p->str=strdup(str);
	//strdup将串拷贝到新建位置处,返回值是一个指向复制字符串分配空间的指针 
	p->next=head;
	return p;
}
HashTable *init_hashtable(int n){//存n个元素的哈希表 
	HashTable*h=(HashTable*)malloc(sizeof(HashTable));
	h->size=n*2;//开大两倍 
	//h->size=n<<1;
	h->data=(Node**)calloc(sizeof(Node*),h->size);//因为要初始化 
	return h;
}
int BKDRHash(char*str){//哈希函数 
	int seed=31;
	int hash=0;
	for(int i=0;str[i];i++){
		hash=hash*seed+str[i];
	}
	return hash & 0x7fffffff;//保证返回的是一个正值 
}
//哈希表的插入 
int insert(HashTable*h,char*str){
	int hash=BKDRHash(str);
	int ind=hash%h->size;//转化成数组下标
	h->data[ind]=init_node(str,h->data[ind]);//头插法 
	return 1; 
} 
//如果用开放定址法 我们会发现拉链法要简单 
/*int insert(HashTable*h,char*str){
	int hash=BKDRHash(str),times=0;
	int ind=has%h->size;
	Node*node=init_node(str,NULL);
	while(h->data[ind]){
		times++;
		ind+=times*times;
		ind%=h->size;
	}
	h->data[ind]=node;
}*/
int search(HashTable*h,char*str){
	int hash=BKDRHash(str);
	int ind=hash%h->size;
	Node*p=h->data[ind];
	while(p && strcmp(p->str,str)){
		p=p->next;
	}
	return p!=NULL;
}
//哈希表的clear
void clear_node(Node*node)
{
	if(node==NULL)return;
	Node*p,*q;
	p=node;//
	while(p!=NULL){
		q=p->next;
		//free(p->next);
		free(p->str);
		free(p);
		p=q;
	}
}
void clear_HashTable(HashTable*h){
	if(h==NULL){
		return;
	}
	for(int i=0;i<h->size;i++){
		clear_node(h->data[i]);
	}
	free(h->data);
	free(h);
	return;
}
int main()
{
	//cout<<"(((";
	//char *str;
	char str[100];
	int op;
	HashTable*h=init_hashtable(10);
	while(scanf("%d %s",&op,str)!=EOF){//建议不要用cin ,咱也不知道为啥,因为它运行不对 
		//cout<<"ss";cin>>op>>str
		if(op%2==0){//插入操作
			cout<<"insert "<<str<<" to hash table"<<endl;
			insert(h,str);
		}
		else{
			cout<<"search:"<<str<<"	result:"<<search(h,str)<<endl;
		}
		
		
	}
	return 0;
 } 

总结

虽然先看了网课,但这个代码演示对之后真的非常快乐,因为改了好多次,有很多的错误。写博客最主要还是为了加深自己对于算法和数据结构的理解,完成之后真的很快乐啊

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值