① 散列表的查找效率主要取決於建表時所選取的散列函數和處理沖突的方法
散列表的查找效益主要取決於建表示所選的散列函數和儲蓄方式的這段換成這個是寫三角函數的處理方法。
② 關於散列表,散列函數的兩個問題。
散列表是一種數據結構,通過散列函數(也就是 hash 函數)將輸入映射到一個數字,一般用映射出的數字作為存儲位置的索引。數組在查找時效率很高,但是插入和刪除卻很低。而鏈表剛好反過來。設計合理的散列函數可以集成鏈表和數組的優點,在查找、插入、刪除時實現 O(1) 的效率。散列表的存儲結構使用的也是數組加鏈表。執行效率對比可以看下圖 1.3:
散列表的主要特點:
將輸入映射到數字
2.不同的輸入產生不同的輸出
3.相同的輸入產生相同的輸出
4. 當填裝因子超過閾值時,能自動擴展。填裝因子 = 散列表包含的元素數 / 位置總數,當填裝因子 =1,即散列表滿的時候,就需要調整散列表的長度,自動擴展的方式是:申請一塊舊存儲容量 X 擴容系數的新內存地址,然後把原內存地址的值通過其中的 key 再次使用 hash 函數計算存儲位置,拷貝到新申請的地址。
5. 值呈均勻分布。這里的均勻指水平方向的,即數組維度的。如果多個值被映射到同一個位置,就產生了沖突,需要用鏈表來存儲多個沖突的鍵值。極端情況是極限沖突,這與一開始就將所有元素存儲到一個鏈表中一樣。這時候查找性能將變為最差的 O(n),如果水平方向填充因子很小,但某些節點下的鏈表又很長,那值的均勻性就比較差。
③ 有一個表長為m的散列表,初始狀態為空,現將n(n<m)個不同的關鍵碼插入到散列表中,解決沖突的方法是用線
假設n個關鍵碼的散列值均為x,那麼:
插入第一個關鍵碼時,檢查x位置,結果為空,直接插入,探測次數為0;
插入第二個關鍵碼時,檢查x位置,結果不為空,採用線性探測法,繼續探測x+1位置,結果為空,插入,探測次數為1;
……
插入第n個關鍵碼時,x位置不為空,從x+1位置開始探測,直至探測到x+(n-1)位置時才為空(這里假設x+(n-1)<m),執行插入操作,探測次數為n-1次。
所以,總的探測次數是一個等差數列,首項為0,公差為1,項數為n,那麼,總次數自然可以用等差數列的求和公式算出,即S=a1+n*(n-1)*b/2=0+n*(n-1)*1/2=n(n-1)/2。
④ 已知散列表長度為13,散列函數為H(key)=key % 11,處理沖突的方法為線性探測法
10%11=10 a[9]=10
8%11=8 a[7]=8
40%11=7 a[6]=40
27%11=5 a[4]=27
21%11=10
57%11=2 a[1]=57
46%11=2
23%11=1 a[0]=23
19%11=8
56%11=1
21和10沖突 且a[10]空 所以a[10]=21
46和57沖突 且a[2]空 所以 a[2]=46
19和8沖突 且a[8]空 所以 a[8]=19
56和23沖突 且a[1]、a[2]不空,a[3]空 a[3]=56
最後是23,57,46,56,27,空,40,8,19,10,21,空,空
查找成功的平均長度:6*1+3*2+1*3=15
查找不成功的平均長度:6+5+4+3+2+1+6+5+4+3+2+1=42
(4)散列表中解決沖突的兩種方法是擴展閱讀:
直接定址法
例如:有一個從1到100歲的人口數字統計表,其中,年齡作為關鍵字,哈希函數取關鍵字自身。
數字分析法
有學生的生日數據如下:
年.月.日
75.10.03
75.11.23
76.03.02
76.07.12
75.04.21
76.02.15
經分析,第一位,第二位,第三位重復的可能性大,取這三位造成沖突的機會增加,所以盡量不取前三位,取後三位比較好。
平方取中法
取關鍵字平方後的中間幾位為哈希地址。
折疊法
將關鍵字分割成位數相同的幾部分(最後一部分的位數可以不同),然後取這幾部分的疊加和(捨去進位)作為哈希地址,這方法稱為折疊法。
例如:每一種西文圖書都有一個國際標准圖書編號,它是一個10位的十進制數字,若要以它作關鍵字建立一個哈希表,當館藏書種類不到10,000時,可採用此法構造一個四位數的哈希函數。
除留余數法
取關鍵字被某個不大於哈希表表長m的數p除後所得余數為哈希地址。
H(key)=key MOD p (p<=m)
隨機數法
選擇一個隨機函數,取關鍵字的隨機函數值為它的哈希地址,即
H(key)=random(key),其中random為隨機函數。通常用於關鍵字長度不等時採用此法。
若已知哈希函數及沖突處理方法,哈希表的建立步驟如下:
Step1.取出一個數據元素的關鍵字key,計算其在哈希表中的存儲地址D=H(key)。若存儲地址為D的存儲空間還沒有被佔用,則將該數據元素存入;否則發生沖突,執行Step2。
Step2.根據規定的沖突處理方法,計算關鍵字為key的數據元素之下一個存儲地址。若該存儲地址的存儲空間沒有被佔用,則存入;否則繼續執行Step2,直到找出一個存儲空間沒有被佔用的存儲地址為止。
⑤ 散列表處理沖突的二次探測法,表長要求是滿足4j+3的質數。但我在做題過程中發現有的表長不滿足這一條
合理誤差
⑥ 哈希查找的解決沖突
影響哈希查找效率的一個重要因素是哈希函數本身。當兩個不同的數據元素的哈希值相同時,就會發生沖突。為減少發生沖突的可能性,哈希函數應該將數據盡可能分散地映射到哈希表的每一個表項中。解決沖突的方法有以下兩種:
(1) 開放地址法
如果兩個數據元素的哈希值相同,則在哈希表中為後插入的數據元素另外選擇一個表項。
當程序查找哈希表時,如果沒有在第一個對應的哈希表項中找到符合查找要求的數據元素,程序就會繼續往後查找,直到找到一個符合查找要求的數據元素,或者遇到一個空的表項。
(2) 鏈地址法
將哈希值相同的數據元素存放在一個鏈表中,在查找哈希表的過程中,當查找到這個鏈表時,必須採用線性查找方法。
例3. 6是一個簡單的哈希查找演算法程序,你可以將它和本章結尾的有關代碼一起編譯連接成一個可執行程序。
例3.6一個簡單的哈希查找演算法程序
1: #include<stdlib.h>
2: #include<string.h>
3: #include list.h
4: #include hash.h
5:
6: #define HASH_SIZE 1024
7:
8: static listnode_t *hashTable[HASH_SIZE];
9:
10: void insert(const char * s)
11: {
12: listnode_t *ele = newNode((void * ) s)
13: unsigned int h = hash(s) % HASH_SIZE;
14:
15: ele->next = hashTable[h]
16: hashTable[h] = ele;
17: }
18:
19: void print (void)
20: {
21: int h;
22:
23: for (h = 0; h < HASH_SIZE; h++)
24: {
25: listnode_t * lp = hashTalbe[h];
26:
27: if(lp == NULL)
28: continue;
29: printf([%d] , h);
30: while (lp)
31: {
32: printf( '%s' , lp->u.str)
33: lp = ip->next;
34: }
35: putchar ('
');
36: }
37: }
38:
39: const char *search(const char *s)
40: {
39: unsigned int h = hash(s) % HASH_SIZE;
42: listnode_t * lp = hashTable[h];
43:
44: while (lp)
45: {
46: if (! strcmp (s, lp->u.str))
47: return lp->u.str;
48: lp = lp->next;
49: }
50: return NULL;
51: }
請參見:
3. 4 哪一種查找方法最方便?
3.5 哪一種查找方法最快?
3.8 怎樣查找鏈表中的數據?
_____________________________________________
以下是一個簡單示例:
#include<iostream>
#include<string>
using namespace std;
#define m 5 //人數
#define n 10 //哈希表長度
#define q 7 //隨機數
struct name{
char *py;
int k;
};
name namelist[n];
struct hash{
char *py;
int k;
int s;
};
hash hashlist[n];
void listname()
{
char *f;
int s0,r,i;
namelist[0].py=as;
namelist[1].py=sa;
namelist[2].py=d;
namelist[3].py=f;
namelist[4].py=g;
for(i=0;i<m;i++)
{
s0=0;
f=namelist[i].py;
for(r=0;*(f+r)!='