zoukankan      html  css  js  c++  java
  • 数据结构之哈希表

    仅给出一个以“除留余数法”+“开放定址法(线性探測再散列)”实现的哈希表代码:

    #pragma once
    
    #define SUCCESS 1
    #define UNSUCCESS 0
    #define DUPLICATE -1
    #define NULLKEY -111
    
    #define OK 1
    #define ERROR -1
    
    #define EQ(a,b) ((a)==(b))
    #define LT(a,b) ((a)< (b))
    #define LQ(a,b) ((a)<=(b))
    
    typedef int KeyType;
    typedef int info;
    
    typedef struct
    {
    	KeyType key;
    	//info otherinfo;
    }ElemType;
    
    typedef struct
    {
    	ElemType *elem;
    	int count;		 //当前hash表元素个数
    	int sizeindex;	 //hashsize[sizeindex]为当前hash表当前容量
    }HashTable;
    
    int InitHashTable(HashTable &H); // 构造一个空的哈希表
    void DestroyHashTable(HashTable &H);
    int Hash(KeyType K); // 除留余数法(m为表长。全局变量)
    void collision(int &p,int d);// 开放定址法处理冲突:线性探測再散列
    int SearchHash(HashTable H,KeyType K,int &p,int &c);   //搜索的是keyword
    int InsertHash(HashTable &H,ElemType e);			   //插入的是元素
    void RecreateHashTable(HashTable &H) /* 重建哈希表 */;
    void TraverseHash(HashTable H);

    #include "hash.h"
    
    #include <stdio.h>
    #include <stdlib.h>
    
    int hashsize[]={13,19,29,37}; // 哈希表容量递增表,一个合适的素数序列
    int m = 0; // 哈希表表长,全局变量
    
    int InitHashTable(HashTable &H)	// 构造一个空的哈希表
    { 
    	int i;
    
    	H.count=0; // 当前元素个数为0
    	H.sizeindex=0; // 初始存储容量为hashsize[0]
    	m = hashsize[0];
    
    	H.elem=(ElemType*)malloc(m*sizeof(ElemType));
    	if(!H.elem)
    		exit(0); // 存储分配失败
    
    	for(i=0;i<m;i++)
    		H.elem[i].key=NULLKEY; // 未填记录的标志
    
    	return OK;
    
    }  //InitHashTable
    
    void DestroyHashTable(HashTable &H)	 //哈希表H存在,销毁哈希表H
    { 
    	if (H.elem != NULL) free(H.elem);
    	H.elem=NULL;
    	H.count=0;
    	H.sizeindex=0;
    } //DestroyHashTable
    
    int Hash(KeyType K)	   // 除留余数法(m为表长。全局变量)
    { 
    	return K%m;
    } //Hash
    
    void collision(int &p,int d) // 开放定址法处理冲突:线性探測再散列
    { 
    	p=(p+d)%m;
    } //collision
    
    //在开放地址hashH中查找keywordK的元素,若查找成功,以p指示待查元素数据在表中位置并返回SUCCESS
    //否则以p指示插入位置并返回UNSUCCESS
    //c用以计冲突次数,其初值为0。供建表插入时參考
    int SearchHash(HashTable H,KeyType K,int &p,int &c)
    {    
    	p=Hash(K); //构造哈希函数
    	while(H.elem[p].key!=NULLKEY&&!EQ(K,H.elem[p].key))
    	{
    		collision(p,++c); //冲突检測
    		if(c>=m) break;
    	}
    
    	if(H.elem[p].key!=NULLKEY&&EQ(K,H.elem[p].key))
    		return SUCCESS;
    	else 
    		return UNSUCCESS;
    }//SearchHash
    
    int InsertHash(HashTable &H,ElemType e)
    { 
    	// 查找不成功时插入数据元素e到开放定址哈希表H中,并返回OK;若冲突次数过大,则重建哈希表
    	int c,p;
    	c=0;
    	if(SearchHash(H,e.key,p,c)) // 表中已有与e有同样keyword的元素
    		return DUPLICATE;
    	else if(c<hashsize[H.sizeindex]/2) // 冲突次数c未达到上限,(c的阀值可调)
    	{
    		// 插入e
    		H.elem[p]=e;
    		++H.count;
    		return OK;
    	}
    	else
    		RecreateHashTable(H); // 重建哈希表
    	return ERROR;
    }
    
    void RecreateHashTable(HashTable &H) // 重建哈希表
    { 
    	int i,count=H.count;
    	ElemType *p,*elem=(ElemType*)malloc(count*sizeof(ElemType));
    	p=elem;
    	printf("重建哈希表
    ");
    
    	for(i=0;i<m;i++) // 保存原有的数据到暂时申请了空间的elem中
    		if((H.elem+i)->key!=NULLKEY) // 该单元有数据
    			*p++=*(H.elem+i);
    
    	H.count=0;
    	H.sizeindex++; // 增大存储容量
    	m=hashsize[H.sizeindex];
    
    	p=(ElemType*)realloc(H.elem,m*sizeof(ElemType));
    	if(!p)
    		exit(-1); // 存储分配失败
    
    	H.elem=p;
    	for(i=0;i<m;i++)
    		H.elem[i].key=NULLKEY; // 未填记录的标志(初始化)
    
    	for(p=elem;p<elem+count;p++) // 将原有的数据依照新的表长插入到重建的哈希表中
    		InsertHash(H,*p);
    
    	free(elem);elem = NULL;
    }//RecreateHashTable
    
    void TraverseHash(HashTable H)
    {
    	int i;
    	for (i = 0; i < m; i++)
    		printf("%2d ", i);
    	putchar('
    ');
    	for (i = 0; i < m; i++)
    		if (H.elem[i].key != NULLKEY)
    			printf("%2d ", H.elem[i].key);
    		else
    			printf("   ");
    	putchar('
    ');
    	putchar('
    ');
    }

    測试代码:

    int main()
    {
    	HashTable H;
    	int i;
    
    	KeyType arr[] = {19, 14, 23, 01, 68, 20, 84, 27, 55, 11, 10, 79};  //keyword
    	int n = sizeof(arr)/sizeof(arr[0]);
    
    	InitHashTable(H);
    	ElemType e;
    	for (i = 0; i < n - 1; i++)//n
    	{
    		e.key = arr[i];
    		InsertHash(H, e);   //插入的是元素
    		printf("插入 %d 后:
    ", e.key);
    		TraverseHash(H);
    	}
    
    	printf("Hash表元素为:
    ");
    	TraverseHash(H);
    
    	for (i = 0; i < n; i++)
    	{
    		int p = 0, c = 0;
    		int ret = SearchHash(H, arr[i], p, c);	//查找的是keyword
    		if(ret)
    			printf("查找 %2d 成功, p = %2d, key = %2d, c = %d
    ",arr[i], p, H.elem[p].key, c);
    		else 
    			printf("查找 %d 失败
    ", arr[i]);
    	}
    
    	DestroyHashTable(H);
    	getchar();
    	return 1;
    }

  • 相关阅读:
    IM的扫码登录功能如何实现?一文搞懂主流的扫码登录技术原理
    IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现
    2020年了,Android后台保活还有戏吗?看我如何优雅的实现!
    P2P技术详解(三):P2P中的NAT穿越(打洞)方案详解(进阶分析篇)
    微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结
    史上最通俗,彻底搞懂字符乱码问题的本质
    你知道,HTTPS用的是对称加密还是非对称加密?
    IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路
    面视必备,史上最通俗计算机网络分层详解
    阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处
  • 原文地址:https://www.cnblogs.com/llguanli/p/6811996.html
Copyright © 2011-2022 走看看