天天看點

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

1.查找

概念

        •設記錄表L=(R1 R2……Rn),其中Ri(l≤i≤n)為記錄,對給定的某個值k,在表L中确定key=k的

記錄的過程,稱為查找。

        •若表L中存在一個記錄Ri的key=k,記為Ri.key=k,則查找成功,傳回該記錄在表L中的序号i(或Ri 的位址),否則(查找失敗)傳回0(或空位址Null)。

方法

        查找方法有順序查找、折半查找、分塊查找、Hash表查找等等。查找算法的優劣将影響到計算機的使用效率,應根據應用場合選擇相應的查找算法。

平均查找長度

        對查找算法,主要分析其T(n)。查找過程是key的比較過程,時間主要耗費在各記錄的key與給定k值的比較上。比較次數越多,算法效率越差(即T(n)量級越高),故用“比較次數”刻畫算法的T(n)。一般以“平均查找長度”來衡量T(n)。

        平均查找長度ASL(Average Search Length):對給定k,查找表L中記錄比較次數的期望值(或平均值),即:

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

Pi為查找Ri的機率。等機率情況下Pi=1/n;Ci為查找Ri時key的比較次數(或查找次數)。 

順序查找算法

        對于順序查找算法,ASL=O(n),效率是很低的,意味着查找某記錄幾乎要掃描整個表,當表長n很大時,會令人無法忍受。

折半查找算法

        對給定值k,逐漸确定待查記錄所在區間,每次将搜尋空間減少一半(折半),直到查找成功或失敗為止。

        設兩個遊标low、high,分别指向目前待查找表的上界(表頭)和下界(表尾)。mid指向中間元素。

分塊查找

1.分塊

        設記錄表長為n,将表的n個記錄分成b=n/s(向上取整)個塊,每塊s個記錄(最後一塊記錄數可以少于s個),即:

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

        且表分塊有序,即第i(1≤i≤b-1)塊所有記錄的key小于第i+1塊中記錄的key,但塊内記錄可以無序。

2.建立索引

每塊對應一索引項:

其中kmax為該塊内記錄的最大key;link為該塊第一記錄的序号(或指針)。

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

 例題

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

總結

        順序、折半、分塊查找和樹表的查找中,其ASL的量級在O(n)~O(log2n)之間。

        不論ASL在哪個量級,都與記錄長度n有關。随着n的擴大,算法的效率會越來越低。

        ASL與n有關是因為記錄在存儲器中的存放是随機的,或者說記錄的key與記錄的存放位址無關,因而查找隻能建立在key的“比較”基礎上。(如何讓查找不建立在比較的基礎之上呢?)

2.hash表原理

2.1概念

        理想的查找方法是:對給定的k,不經任何比較便能擷取所需的記錄,其查找的時間複雜度為常數級O(C)。

        這就要求在建立記錄表的時候,确定記錄的key與其存儲位址之間的關系f,即使key與記錄的存放位址H相對應:

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

        當要查找key=k的記錄時,通過關系f就可得到相應記錄的位址而擷取記錄,進而免去了key的比較過程。

        這個關系f就是所謂的Hash函數(或稱散列函數、雜湊函數),記為H(key)。

        它實際上是一個位址映象函數,其自變量為記錄的key,函數值為記錄的存儲位址(或稱Hash位址)。

        不同的key可能得到同一個Hash位址,即當key1≠key2時,可能有H(key1)=H(key2),此時稱key1和key2為同義詞。這種現象稱為“沖突”或“碰撞”,因為一個資料機關隻可存放一條記錄。

        一般,選取Hash函數隻能做到使沖突盡可能少,卻不能完全避免。這就要求在出現沖突之後,尋求适當的方法來解決沖突記錄的存放問題。

        根據選取的Hash函數H(key)和處理沖突的方法,将一組記錄(R1 R2……Rn)映象到記錄的存儲空間,所得到的記錄表稱為Hash表,如圖:

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

        選取(或構造)Hash函數的方法很多,原則是盡可能将記錄均勻分布,以減少沖突現象的發生。以下介紹幾種常用的構造方法。

        直接位址法

        平方取中法

        疊加法

        保留除數法

        随機函數法

2.2保留除數法

        又稱質數除餘法,設Hash表空間長度為m,選取一個不大于m的最大質數p,令:          H(key)=key%p。(質數:指在大于1的自然數中,除了1和它本身以外不再有其他因數的自然數。)

舉例

        設記錄的key集合k={28,35,63,77,105……},若選取p=21=3*7(包括質數因子7),有:

                   key:28  35  63  77  105  ……

                   H(key)=key%21: 7   14   0   14    0    ……

        使得包含質數因子7的key都可能被映象到相同的單元,沖突現象嚴重。

        若取p=19(質數),同樣對上面給定的key集合k,有:

                   key:28  35  63  77  105

                   H(key)=key%19: 9   16   6    1    10

            H(key)的随機度就好多了。

2.3處理沖突的方法

        選取随機度好的Hash函數可使沖突減少,一般來講不能完全避免沖突。設Hash表位址空間為0~m-l(表長為m):

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

         沖突是指:表中某位址j∈[0,m-1]中己存放有記錄,而另一個記錄的H(key)值也為j。

        處理沖突的方法一般為:在位址j的前面或後面找一個空閑單元存放沖突的記錄,或将相沖突的諸記錄拉成連結清單。

        在處理沖突的過程中,可能發生一連串的沖突現象,即可能得到一個位址序列H1、H2……Hn,Hi∈[0,m-l]。H1是沖突時選取的下一位址,而H1中可能己有記錄,又設法得到下一位址H2……直到某個Hn不發生沖突為止。這種現象稱為“聚積”,它嚴重影響了Hash表的查找效率。

        沖突現象的發生有時并不完全是由于Hash函數的随機性不好引起的,聚積的發生也會加重沖突。

        還有一個因素是表的裝填因子α,α=n/m,其中m為表長,n為表中記錄個數。一般α在0.7~0.8之間,使表保持一定的空閑餘量,以減少沖突和聚積現象。

2.3.1開放位址法

        當發生沖突時,在H(key)的前後找一個空閑單元來存放沖突的記錄,即在H(key)的基礎上擷取下一位址:

                            Hi = ( H(key) + di ) % m

其中m為表長,%運算是保證Hi落在[0,m-l]區間;di為位址增量。di的取法有多種:

    (1)di=1,2,3,……(m-1)——稱為線性探查法;

    (2)di=1^2,-1^2,2^2,-2^2,……——稱為二次探查法。

舉例

        設記錄的key集合k={23,34,14,38,46,16,68,15,07,31,26},記錄數n=11。

令裝填因子α=0.75,取表長m= n/α =15(向上取整)。

用“保留餘數法”選取Hash函數(p=13):

                                       H(key) = key % 13

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

68對13取餘等于3,和16重複了,故帶入公式3+1對15取餘等于4,故68放到4的位置 ,其他同理

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

2.3.2鍊位址法

        發生沖突時,将各沖突記錄鍊在一起,即同義詞的記錄存于同一連結清單。

        設H(key)取值範圍(值域)為[0,m-1],建立頭指針向量HP[m],HP[i](0≤i≤m-l)初值為空。 

 設H(key)=key%13,k={ 23,34,14,38,46,16,68,15,07,31,26 }

【資料結構筆記】資料結構基礎—查找1.查找2.hash表原理3.hash表的實作相關題目

鍊位址法解決沖突的優點:無聚積現象;删除表中記錄容易實作。

3.hash表的實作

#define N 15
typedef int datatype;

typedef struct node {  // 鍵值對兒,這裡和python的字典有點不一樣
	datatype key;		// 值
	datatype value; // 是H(key),即key所對應的位置
	struct node * next;
}listnode, *linklist;

typedef struct {
	listnode data[N];
}hash;
           

建立

hash * hash_create() {
	hash * HT;  // 整個hash表

	if ((HT = (hash *)malloc(sizeof(hash))) == NULL) {
		printf("malloc failed\n");
		return NULL;
	}

	memset(HT, 0, sizeof(hash)); // 這樣寫效率更高,使得諸如data[11].key、data[11].value都為0

	return HT;
}
           

插入

int hash_insert(hash *HT, datatype key) {
	linklist p, q;

	if (HT == NULL) {
		printf("HT is NULL\n");
		return -1;
	}

	if ((p = (linklist)malloc(sizeof(listnode))) == NULL) { // 建立新節點
		printf("malloc failed\n");
		return -1;
	}
  // 初始化新節點中的值
	p->key = key;
	p->value = key % N;
	p->next = NULL;

	q = &(HT->data[key % N]); // HT->data[key % N]是一個節點,此時q指向hash表中key待插入的位置

// 如果q->next為1,表明key的待插入位置(即H(key))已經插入過節點了
// 由于插入是順序插入,是以要比較新插入的節點的key和已有的節點的key哪個大,大的放後面
	while (q->next && q->next->key < p->key ) {
		q = q->next;
	}

	p->next = q->next;
	q->next = p;

	return 0;

}
           

查找

// 先找hash表中對應的位置,再看這個位置有沒有重複的
linklist  hash_search(hash *HT, datatype key) {
	linklist p;

	if (HT == NULL) {
		printf("HT is NULL\n");
		return NULL;
	}

	p = &(HT->data[key % N]);

	while (p->next && p->next->key != key) {
		p = p->next;
	}

	if (p->next == NULL) {
		return NULL;
	} else {
		printf("found\n");
		return p->next;
	}
}
           

相關題目

1、下面關于二分查找的叙述正确的是( )。

A.表必須有序,表可以順序方式存儲,也可以連結清單方式存儲

B.表必須有序且表中資料必須是整型,實型或字元型

C.表必須有序,而且隻能從小到大排列

D.表必須有序,且表隻能以順序方式存儲

2、請說出順序表查找的特點?

3、設hash表長度為14,hash函數是 H(key) = key % 11 ,表中已有資料的關鍵字為15,38,61,84共四個,現要将關鍵字為49的結點加到表中,用二次探查法處理沖突,則放入的位置是( )。

A.8 B. 3 C. 5 D. 9

4、将10個元素散列到100000個單元的哈希表中,則( )産生沖突。

A. 一定會 B. 一定不會 C. 仍可能會

5、已知一個線性表(38,25,74,63,52,48),采用的散列函數為H(Key)=Key mod 7,将元素散列到表長為7的哈希表中存儲。若采用線性探測的開放定址法解決沖突,則在該散清單上進行等機率成功查找的平均查找長度為 __________。

A. 1.5 B. 1.7 C. 2.0 D. 2.3

答案

1.D

2.算法簡單,對表的結構無任何要求,無論是用向量還是用連結清單來存放結點,也無論結點之間是否按關鍵字有序,它都同樣适用。

但查找效率低,是以,當表長較大時不宜采用順序查找。

3.D

4.C

5.C,38-3(1次)25-4(1次)74-5(2次)63-0(1次)52-6(4次)48-1(3次)故計算的(1+1+2+1+4+3)/6=2

繼續閱讀