数据结构:散列表(哈希表)
来源:互联网 发布:客户经理好用软件 编辑:程序博客网 时间:2024/06/06 04:13
概念:
在理想情况下,散列表数据结构就是一个某种数据类型的具有固定大小的数组。在数组用于保存某一集合的数据。集合中的元素根据某种运算(散列函数)得到相应的小标。理想情况下,不同的元素对应不同的下标。如果不同的元素对应相同的下标,那么我们称这种情况为冲突。
散列函数多种多样,根据不同的情况选择不同的函数,散列函数一般有哪些,自己查课本。那么出现冲突时,有几种解决方法,这里,我们将讨论最简单的两种。(分离链表法,开放定址法)
一、分离链表法。
做法:可以把散列表看成结构体数组,并分别形成一个链表。将散列到同一个值的所有元素保留到同一个链表中。
1,利用线性探测法构造散列表
题目:已知一组关键字为(26,36,41,38,44,15,68,12,06,51),用除余法构造散列函数,用线性探查法解决冲突构造这组关键字的散列表。
解答:为了减少冲突,通常令装填因子α<=0.5。这里关键字个数n=10,不妨取m=19(一般是素数),此时α≈0.526,散列表为T[0..18],散列函数为:hi(key)=(key+i)%19。(i=[0...18])
由除余法的散列函数计算出的上述关键字序列的散列地址为(7,17,3,0, 6,15,9,12,6,13)。
前8个关键字插入时,其相应的地址均为开放地址,故将它们直接插入T[7],T[17),T[3],T[0],T[6),T[15],T[9]和T[12]中。
当插入第9个关键字06时,其散列地址6已被关键字44占用。故探查h1=(6+1)%19=7,此地址也被关键字26占用,故探查h2=(6+2)%19=8
所以将6放入T[8]中。
当插入第10个关键字51时,其散列地址为开放地址。故将其插入到T[13]中。
2、 利用平方探测法构造散列表
平方探测是消除线性探测中一次聚集问题的冲突解决方法。
由上例可知,当hi(key)=(key+i)%19。(i=[0...18])改成hi(key)=(key+i^2)%19。(i=[0...18])就是了。
3、利用双散列构造散列表
基本原理都是一样的,而双散列hi(key)=i*(key%19);但是这种做法是存在灾难性结果的,因为若key为19的话,则i不起作用,
因此我们常常用hash(key)= R-(key%R) R为小于TableSize的素数。所以有hi(key)=i*(R-(key%R));
所以hash()函数的选择相当重要。
在理想情况下,散列表数据结构就是一个某种数据类型的具有固定大小的数组。在数组用于保存某一集合的数据。集合中的元素根据某种运算(散列函数)得到相应的小标。理想情况下,不同的元素对应不同的下标。如果不同的元素对应相同的下标,那么我们称这种情况为冲突。
散列函数多种多样,根据不同的情况选择不同的函数,散列函数一般有哪些,自己查课本。那么出现冲突时,有几种解决方法,这里,我们将讨论最简单的两种。(分离链表法,开放定址法)
一、分离链表法。
做法:可以把散列表看成结构体数组,并分别形成一个链表。将散列到同一个值的所有元素保留到同一个链表中。
相关的代码如下所示:
#include<stdio.h>#include<stdlib.h>//程序中不考虑malloc失败的情况,老是检查,太累了。typedef struct listnode{struct listnode *next;int element;}listnode;typedef struct hashtable{int tablesize;listnode **list;}hashtable;hashtable *initial_hashtable(int );int hashfuntion(int,int);listnode *find(int,hashtable *);void insert(int,hashtable *);void Retrieve(hashtable *);void DestoryTable(hashtable *);hashtable *initial_hashtable(int tablesize){int i;hashtable *h;h=(hashtable *)malloc(sizeof(hashtable));h->tablesize = tablesize;//开始,很好奇明明h->list申请了tablesize个地址空间,可是为什么//h->list[i]还要申请地址空间呢?他们到底有什么区别呢?// h->list申请的是指向listnode *的地址空间//而h->list[]申请的是listnode *的地址空间,是不一样的概念h->list = (listnode **)malloc(sizeof(listnode)*tablesize);for(i=0;i<tablesize;i++){h->list[i]=(listnode *)malloc(sizeof(listnode));h->list[i]->next=NULL;h->list[i]->element =0;}return h;}//哈希函数为对tablesize取模int hashfuntion(int key,int tablesize){return key%tablesize;}listnode *find(int key,hashtable *h){int index;listnode *p;index = hashfuntion(key,h->tablesize);p = h->list[index]->next;while(p!=NULL){if(p->element==key){return p;}p=p->next;}return NULL;}void insert(int key,hashtable *h){int index;listnode *p,*newnode;p=find(key,h);if(p!=NULL){return;}index = hashfuntion(key,h->tablesize);p= h->list[index];while(p->next!=NULL){p=p->next;}newnode=(listnode *)malloc(sizeof(listnode));newnode->element=key;newnode->next=NULL;p->next=newnode;return;}void Retrieve(hashtable *h){int i;listnode *p;for(i=0;i<h->tablesize;i++){p=h->list[i];while(p->next!=NULL){p=p->next;printf("%d ",p->element);}printf("%s","---");}}void DestoryTable(hashtable *h){int i;listnode *p,*L;for(i=0;i<h->tablesize;i++){p=h->list[i];while(p->next!=NULL){L=p;p=p->next;free(L);}}free(h->list);free(h);}void main(){//测试代码int a[]={0,1,2,3,4,5,6,7,8,9,10,11,12};int i;hashtable *h;h= initial_hashtable(5);for(i=0;i<13;i++){insert(a[i],h);}Retrieve(h);}二、对于开放定址法,一般有以下三种方法解决冲突
1,利用线性探测法构造散列表
题目:已知一组关键字为(26,36,41,38,44,15,68,12,06,51),用除余法构造散列函数,用线性探查法解决冲突构造这组关键字的散列表。
解答:为了减少冲突,通常令装填因子α<=0.5。这里关键字个数n=10,不妨取m=19(一般是素数),此时α≈0.526,散列表为T[0..18],散列函数为:hi(key)=(key+i)%19。(i=[0...18])
由除余法的散列函数计算出的上述关键字序列的散列地址为(7,17,3,0, 6,15,9,12,6,13)。
前8个关键字插入时,其相应的地址均为开放地址,故将它们直接插入T[7],T[17),T[3],T[0],T[6),T[15],T[9]和T[12]中。
当插入第9个关键字06时,其散列地址6已被关键字44占用。故探查h1=(6+1)%19=7,此地址也被关键字26占用,故探查h2=(6+2)%19=8
所以将6放入T[8]中。
当插入第10个关键字51时,其散列地址为开放地址。故将其插入到T[13]中。
2、 利用平方探测法构造散列表
平方探测是消除线性探测中一次聚集问题的冲突解决方法。
由上例可知,当hi(key)=(key+i)%19。(i=[0...18])改成hi(key)=(key+i^2)%19。(i=[0...18])就是了。
3、利用双散列构造散列表
基本原理都是一样的,而双散列hi(key)=i*(key%19);但是这种做法是存在灾难性结果的,因为若key为19的话,则i不起作用,
因此我们常常用hash(key)= R-(key%R) R为小于TableSize的素数。所以有hi(key)=i*(R-(key%R));
所以hash()函数的选择相当重要。
我们以其中的第一种方法为例,写出以下代码:
//在散列表中删除操作一般都选择懒惰删除,所谓的懒惰就是在删除数的位置标记为//deleted状态#include<stdio.h>#include<stdlib.h>#define Legitimate 0#define Empty 1#define Deleted 2#define divided 19typedef struct HashEntry{int element;int info;}HashEntry;typedef struct HashTable{int TableSize;HashEntry *he;}HashTable;HashTable *Initial_Table(int);void DestroyTable(HashTable *);int Find(int ,HashTable *);void Insert(int ,HashTable *);int Retrieve(int ,HashTable *);int HashFuntion(int,int);void error(char *);void error(char *c){//略}void DestroyTable(HashTable *H){//略}int HashFuntion(int key,int i){return (key+i)%divided;}int Retrieve(int p,HashTable *H){//略。。return 0;}void Insert(int key,HashTable *H){int index;int i;for(i=0;i<divided;i++){index= HashFuntion(key,i);if(H->he[index].info == Empty){H->he[index].info = Legitimate;H->he[index].element = key;return;}}error("out of space");}int Find(int key,HashTable *H){int i;for(i=0;i<H->TableSize;i++){if(H->he[i].element ==key && H->he[i].info == Legitimate){return i;}}error("not be found");return 0;}HashTable *Initial_Table(int TableSize){int i;HashTable *H=(HashTable *)malloc(sizeof(HashTable));H->TableSize = TableSize;H->he=(HashEntry *)malloc(sizeof(HashEntry)*TableSize);for(i=0;i<TableSize;i++){H->he[i].element = 0;H->he[i].info = Empty;}return H;}void main(){//测试代码int i;int index;int a[]={26,36,41,38,44,15,68,12,06,51};HashTable *H = Initial_Table(19);for(i=0;i<10;i++){Insert(a[i],H);}index=Find(06,H);printf("06的散列地址是:%d",index);}
- 数据结构:散列表(哈希表)
- 数据结构:哈希表(散列表)
- 数据结构---哈希表/散列表
- 【数据结构】哈希表/散列表
- 数据结构-散列表 哈希表
- HashSet、HashMap,散列表数据结构(哈希表)
- [数据结构]程杰:散列表(哈希表)
- 数据结构——哈希表(散列表)
- HashSet、HashMap,散列表数据结构(哈希表)
- 数据结构_____散列表查找(哈希表)
- 数据结构之哈希表(散列表查找)
- 数据结构之散列表(哈希表)
- 《数据结构》之(散列表)
- 数据结构学习笔记(十)哈希表(散列表)
- 大话数据结构读书笔记(6)----散列表(哈希表)
- 一点一点学数据结构之哈希表(散列表)
- 【学习笔记----数据结构26-散列表查找(哈希表)】
- 大话数据结构—散列表查找(哈希表)
- 杭电OJ题1018 Big Number 解题报告
- css显示倒置柱状图,认识bottom属性
- java异常收集与整理
- MFC 2008,新的用户界面 - 1 - 框架窗口
- 注重纪律——读《浮现式设计》有感
- 数据结构:散列表(哈希表)
- MFC 2008,新的用户界面 - 2 - 应用程序类
- MFC 2008,新的用户界面 - 3 - 菜单栏、工具栏和状态栏
- uva 112 TreeSumming
- 技术人员的未来:做技术还是做管理?
- bootClassPath
- android 自适应 多屏幕支持
- 同志们,换美元去购买世界吧
- mysqldump 备份报错