演算法導論-第11章-散列表

來源:互聯網
上載者:User
一、概念1.綜述散表表僅支援INSERT、SEARCH、DELETE操作。把關鍵字k映射到槽h(k)上的過程稱為散列。多個關鍵字映射到同一個數組下標位置稱為碰撞。好的散列函數應使每個關鍵字都等可能地散列到m個槽位中2.散表函數

(1)若函數為h(k)=k,就是直接定址表

(2)除法散列法:h(k) = k mod m

(3)乘法散列法:h(k) = m * (k * A mod 1) (0<A<1)

(4)全域散列:從一組仔細設計的散列函數中隨機地選擇一個。(即使對同一個輸入,每次也都不一樣,平均性態較好)

3.衝突解決方案策略

(1)連結法

(2)開放定址法

a.線性探測:h(k, i) = (h'(k) + i) mod m

b.二次探測:h(k, i) = (h'(k) + c1*i + c2 *i^2) mod m

c.雙重散列:h(k, i) = (h1(k) + i * h2(k)) mod m

(3)完全散列:設計一個較小的二次散列表

 

二、代碼代碼中用到了函數指標,函數指標的用法參考函數指標總結
//Hash.h#include <iostream>using namespace std;int m, NIL = 0;//11.4 開放定址法typedef int (*Probing)(int k, int i);int h(int k){return k % m;}int h2(int k){return 1 + k % (m-1);}//線性探測int Linear_Probing(int k, int i){return (h(k) + i) % m;}//二次探測int Quadratic_Probint(int k, int i){int c1 = 1, c2 = 3;return (h(k) + c1 * i + c2 * i * i) % m;}//雙重探測int Double_Probint(int k, int i){return (h(k) + i * h2(k)) % m;}int Hash_Insert(int *T, int k, Probing p){int i = 0, j;do{j = p(k, i);if(T[j] == NIL){T[j] = k;return j;}i++;}while(i != m);cout<<"error:hash table overflow"<<endl;}int Hash_Search(int *T, int k, Probing p){int i = 0, j;while(1){j = p(k, i);if(T[j] == NIL || i == m)break;if(T[j] == k)return j;i++;}}
三、習題11.1 直接定址表

11.1-1O(m),最壞情況時,集合中只有一個最小關鍵字11.1-2如果插入x,就把向量的第x位置為1如果刪除x,就把向量的第x位置為011.1-3當存在關鍵字為key的衛星資料時,T[key]指向其中一個關鍵字為key的衛星資料。若不存在,T[key]指向空。每一個衛星資料用一個結點表示,結點中有三個域,分別是:關鍵字key,衛星資料data,指向下一個所有相同關鍵字的衛星資料的指標nextDIRECT-ADDRESS-SEARCH(T, k)return T[k];DIRECT-ADDRESS-INSERT(T, x)if T[key[x]] = NULLthenT[key[x]] <- xelse next[x] <- next[T[key[x]]]next[T[key[x]]] <- x

11.1-4 見演算法導論-11.1-4

用一個棧來儲存實際插入的資料,插入時棧向上擴充一個空間,刪除時,用棧頂元素補充被刪除元素的位置,棧向下回收一個空間,方法類似於P127-11.3-4.

這個非常大的數組中不直接存放資料,而是存放資料在Stack中的位置。

對於一個元素p,如果H[p] < 棧中總元素的個數 && p = Stack[H[p]],就是存入,否則就是不存在

 

11.2 散列表

11.2-3

所有操作的時間都是O(n/2),n是一個鏈表的長度

11.2-4 見演算法導論-11.2-4

插入操作時,從自由鏈表中取出一個空閑slot,填入關鍵字x,修改指標,鏈表相應的隊列中,具體可以分為以下幾種情況:

(1)x所屬的slot未被佔用,則

step1:把這個slot從自由鏈表中移出

step2:填入關鍵字x

step3:修改指標,在這種情況下其next和pre都置為-1

(2)x所屬的slot已經被佔用,令佔用這個slot的關鍵是y,y也屬於這個slot,則

step1:從自由鏈表中取出一個閒置slot,這個slot肯定不是x所屬的slot,只是拿過來用

step2:填入關鍵字x

step3:修改指標,把slot鏈表入到“以x所屬的slot為頭結點的隊列”中

(3)x所屬的slot已經被佔用,令佔用這個slot的關鍵是y,y不屬於這個slot,通過(2)可知,這個情況是有可能的

step1:從自由鏈表中取出一個閒置slot,這個slot肯定不是x所屬的slot,也不是y所屬的slot,只是拿過來用

step2:在新slot中填入關鍵字y,修改指標,讓y使用這個新slot,而把原來的slot空出來還給x

step3:在x所屬的slot中填入關鍵字x

step4:修改“x所屬的slot”指標,類似(1)-step3

刪除操作時,令待刪除的關鍵字是x,釋放x所佔用的slot,具體可以分為以下幾種情況

(1)x所佔用的slot正是x所屬的slot,且slot->next=-1,即所有關鍵字中只有x屬於這個slot,x被刪除後,slot就空閑了

step1:釋放slot到自由鏈表中

(2)x所佔用的slot正是x所屬的slot,但還有別的關鍵字中只有x屬於這個slot,應該優先使用關鍵所屬於的slot,而釋放“不自己關鍵字的、臨時拿過來用的”slat

step1:從以slot為頭結點的隊列中另選一個slot2,slot2的關鍵字屬於slot而不屬於slot2,只是因為slot被佔用,所以才用slot2

step2:把slot2的內容填入slot

step3:修改指標,讓slot代替slot2存在於隊列中,不同的是slot還是隊列頭

step4:釋放slot2到自由鏈表中

(3)x所佔用的slot不是x所屬的slot,這個種情況下,這個slot一定不是隊列頭,還有別的關鍵字存在於隊列中,並且佔用了x所屬的slot

step1:把x所佔用的slot從“以x所屬的slot為頭的隊列”中移出

step2:釋放slot到自由鏈表中

尋找操作,如果理解了插入和刪除,尋找操作就比較簡單了,令待尋找的關鍵字是x,也可分為幾種情況

(1)x所屬的slot未被佔用,即不存在與x相同slot的關鍵字,當然也不存在x了

(2)x所屬的slot被佔用了,但它所存的關鍵不屬於這個slot,與(1)相同,不存在與x相同slot的關鍵字

(3)x所屬的slot被佔用了,且它所存的關鍵屬於這個slot,即存在與x相同slot的關鍵字,只是不知這個關鍵字是不是x,需要進一步尋找

 

11.3 散列函數

11.3-1

從散列表中的第h(k)個表中搜尋索引鍵為k的一項

11.3-2

每處理字串中的一個字元,就取一次模

11.3-4

#include <cmath>int main(){int n;while(cin>>n){double A = (sqrt(5.0)-1) / 2;double t1 = A * n;int t2 = (int)t1;double t3 = t1 - t2;int t4 = t3 * 1000;cout<<t4<<endl;}}

h(61) = 700

h(62) = 318

h(63) = 936

h(64) = 554

h(65) = 172

 

11.4 開放定址法

11.4-1

線性探測:22 88 0 0 4 15 28 17 59 31 10

二次探測:22 0 88 17 4 0 28 59 15 31 10

雙重探測:22 0 59 17 4 15 28 88 0 31 10

代碼如下:代碼中用到了函數指標,函數指標的用法參考函數指標總結

#include <iostream>#include <string>#include "Hash.h"using namespace std;void Print(int *T){int i;for(i = 0; i < m; i++)cout<<T[i]<<' ';cout<<endl;}int main(){string str;int i, j;m = 11;int T[11], A[9] = {10, 22, 31, 4, 15, 28, 17, 88, 59};Probing P[3] = {Linear_Probing, Quadratic_Probint, Double_Probint};for(i = 0; i < 3; i++){memset(T, 0, sizeof(T));for(j = 0; j < 9; j++)Hash_Insert(T, A[j], P[i]);Print(T);}return 0;}

11.4-2

刪除一個元素後,將這個位置置為DELETED,在插入操作中,L3改為if T[j] = NIL or T[j] = DELETED

#define DELETED -1int Hash_Insert(int *T, int k, Probing p){int i = 0, j;do{j = p(k, i);if(T[j] == NIL || T[j] == DELETED){T[j] = k;return j;}i++;}while(i != m);cout<<"error:hash table overflow"<<endl;}void Hash_Delete(int *T, int k, Probing p){int j = Hash_Search(T, k, p);if(j != NIL)T[j] = DELETED;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.