1、背景引入
(1)線性表和樹等線性結構中,記錄在結構中的相對位置是隨機的,和記錄的關鍵字之間不存在確定的關系,因此,在結構中查找記錄時需要進行一系列和關鍵字的比較。理想的情況是希望不經過任何比較,一次存取便能夠取到所查找的記錄,那就必須在記錄的存儲位置和它的關鍵字之間建立一個確定的對應關系f,使得每個關鍵字和結構中一個唯一的存儲位置相對應。因而在查找時,只要根據這個對應關系f找到給定值K的像f(K)。若結構中存在關鍵字和K相等的記錄,則必定在f(K)的存儲位置上,因此,不需要進行比較便可以直接取得所查記錄。在此,我們稱這個對應關系f為哈希函數,按照這個思想建立的表為哈希表。
哈希函數的構造方法很多,常用的有直接定址法、數字分析法、平方取中法、折疊法、除留余數法、隨機數法等,,這里我選擇了除留余數法。
(2)然而,對於不同的關鍵字可能得到同一哈希地址,即key1!=key2,而f(key1)=f(key2),這種現象叫做沖突,在一般情況下,沖突只能盡可能的少,而不能完全避免。因為,哈希函數是從關鍵字集合到地址集合的映像。通常,關鍵字集合比較大,它的元素包括多有可能的關鍵字,而地址集合的元素因為哈希表中的地址值。既然如此,那么,如何處理沖突則是構造哈希表不可缺少的一個方面了。。
通常用於處理沖突的方法有:開放定址法、再哈希法、鏈地址法、建立一個公共溢出區等。。。
(3)在哈希表上進行查找的過程和哈希造表的過程基本一致。給定K值,根據造表時設定的哈希函數求得哈希地址,若表中此位置沒有記錄,則查找不成功;否則比較關鍵字,若何給定值相等,則查找成功;否則根據處理沖突的方法尋找“下一地址”,知道哈希表中某個位置為空或者表中所填記錄的關鍵字等於給定值時為止。
2、問題描述
編寫Hash表程序(女友軟件技術基礎的作業,要求哈希表、矩陣運算等,這里是哈希表的實現。。。)
關鍵字為整數,沖突解決用單向鏈表
Hash表建立函數 關鍵字搜素函數
3、解決方法:
(1)采用除留余數法構造哈希函數,沖突解決采用鏈地址法。
(2)具體的關鍵字列表為(19,14,23,01,68,20,84,27,55,11,10,79),則哈希函數為H(key)=key MOD 13。則采用除留余數法和鏈地址法后得到的預想結果應該為:
(3)哈希造表完成后,進行查找時,首先是根據哈希函數找到關鍵字的位置鏈,然后在該鏈中進行搜索,如果存在和關鍵字值相同的值,則查找成功,否則若到鏈表尾部仍未找到,則該關鍵字不存在。
4、具體的實現代碼:
其中2.txt中內容為:12
19 14 23 1 68 20 84 27 55 11 10 79 第一個值12表示關鍵字的個數。其他為具體的關鍵字

1 #include<stdio.h> 2 #include<stdlib.h> 3 struct keyNum*hash[100]; 4 struct keyNum* insertHash(struct keyNum*,int);//關鍵字插入鏈表 5 int searchHash(struct keyNum*,int m);//查找鏈表中是否存在值為m的整數 6 void print(struct keyNum*);//打印鏈表 7 struct keyNum 8 { 9 int key;//關鍵字 10 struct keyNum *next; 11 }; 12 void main() 13 { 14 printf("關鍵字列表保存在2.txt文件中,其中第一個值為關鍵字的個數\n其他值為具體的關鍵字,各個關鍵字之間用空格隔開\n"); 15 int i,k,m,n,num,flag,l,j; 16 FILE *p; 17 struct keyNum *head=NULL; 18 //關鍵字列表保存在2.txt文件中,其中第一個值為關鍵字的個數 19 //其他值為具體的關鍵字,各個關鍵字之間用空格隔開 20 p=fopen("2.txt","r"); 21 if(p==NULL) 22 { 23 printf("cannot open file 2.txt"); 24 exit(0); 25 } 26 fscanf(p,"%d",&num); 27 for(i=0;i<num;i++) 28 hash[i]=NULL; 29 for(i=0;i<num;i++) 30 { 31 fscanf(p,"%d",&k);//獲取關鍵字 32 m=k%(num+1);//計算得到關鍵字的哈希值 33 hash[m]=insertHash(hash[m],k);//將關鍵字k插入到哈希值為m的鏈表中 34 } 35 printf("-----------------------------------------------\n請選擇要進行的操作:\n1、打印采用鏈地址法得到的哈希表\n"); 36 printf("2、進行關鍵字查找\n3、退出\n------------------------------------------------\n"); 37 scanf("%d",&flag); 38 while((flag==1)||(flag==2)) 39 { 40 if(flag==1)//打印哈希表 41 { 42 printf("采用鏈地址法得到的哈希表為:\n"); 43 for(i=0;i<num+1;i++) 44 { 45 printf("第%d行:",i); 46 print(hash[i]); 47 printf("\n"); 48 } 49 } 50 else //查找 51 { 52 printf("請輸入要查找的整數值:\n"); 53 scanf("%d",&n); 54 for(i=0;i<num+1;i++) 55 { 56 l=searchHash(hash[i],n); 57 if(l==1) 58 { 59 j=i; 60 break; 61 } 62 } 63 if(l==1)printf("整數值%d在哈希表中,位置為鏈表%d\n",n,j); 64 else printf("整數值%d不在哈希表中!\n"); 65 } 66 printf("-----------------------------------------------\n請選擇要進行的操作:\n1、打印采用鏈地址法得到的哈希表\n"); 67 printf("2、進行關鍵字查找\n3、退出\n------------------------------------------------\n"); 68 scanf("%d",&flag); 69 } 70 } 71 struct keyNum * insertHash(struct keyNum*head,int m) 72 { 73 struct keyNum *p0,*p1,*p2,*temp; 74 temp=(struct keyNum*)malloc(sizeof(struct keyNum)); 75 temp->key=m; 76 p1=head; 77 p0=temp;//要插入的節點(值為m); 78 if(head==NULL)//1,原來的鏈表為空,插入到head后 79 { 80 head=p0; 81 p0->next=NULL; 82 } 83 else//原來的鏈表不為空 84 { 85 while((p0->key>p1->key)&&(p1->next!=NULL))//移動到適當位置 86 { 87 p2=p1; 88 p1=p1->next; 89 } 90 if(p0->key<=p1->key) 91 { 92 if(head==p1)head=p0;//2,插入到第一個節點之前 93 else p2->next=p0;//3,插入到p2指向的節點之后 94 p0->next=p1; 95 } 96 else//4,插入到結尾處 97 { 98 p1->next=p0; 99 p0->next=NULL; 100 } 101 } 102 return(head); 103 } 104 int searchHash(struct keyNum*head,int m)//查找鏈表head中是否存在m 105 { 106 int k=0; 107 struct keyNum*p; 108 p=head; 109 if(head!=NULL) 110 do 111 { 112 if(p->key==m) //存在m 113 { 114 k=1; 115 break; 116 } 117 p=p->next; 118 }while(p!=NULL); 119 return(k);//存在m值則返回1,否則返回0; 120 } 121 122 void print(struct keyNum*head)//打印鏈表head 123 { 124 struct keyNum*p; 125 p=head; 126 if(head!=NULL) 127 { 128 do 129 { 130 printf(" -> %d ",p->key); 131 p=p->next; 132 }while(p!=NULL); 133 } 134 else 135 printf("null"); 136 } 137 138 139 140 141
5、參考:
(1)數據結構,嚴蔚敏