第 10 章 資料搜尋(Searching)

59
10 10 第第第第第第第第Searching Searching 10-1 10-1 第第第第第 第第第第第 10-2 10-2 第第第第第 第第第第第 第第第第第 第第第第第 10-3 10-3 第第第第第第第第第 第第第第第第第第第 10-4 10-4 第第第第第第第第 第第第第第第第第 10-5 10-5 第第第第第 第第第第第 10-6 10-6 第第第第第第第第第 第第第第第第第第第

description

第 10 章 資料搜尋(Searching). 10-1 搜尋的基礎 10-2 循序搜尋法 – 未排序資料 10-3 已排序資料的搜尋法 10-4 二元搜尋樹搜尋法 10-5 雜湊搜尋法 10-6 雜湊函數的碰撞問題. 10-1 搜尋的基礎 - 說明. 「搜尋」( Searching )是在資料中找尋特定的值,這個值稱為「鍵值」( Key )。例如:在電話簿以姓名找尋朋友電話號碼,姓名就是鍵值,或在書局以書號的鍵值找尋喜愛的書。 搜尋的目的是為了確定資料中是否存在與鍵值相同的資料。. 10-1 搜尋的基礎 - 範例. - PowerPoint PPT Presentation

Transcript of 第 10 章 資料搜尋(Searching)

第第 1010 章 章 資料搜尋資料搜尋(( SearchingSearching))

10-1 10-1 搜尋的基礎搜尋的基礎 10-2 10-2 循序搜尋法 循序搜尋法 – – 未排序資料未排序資料 10-3 10-3 已排序資料的搜尋法已排序資料的搜尋法 10-4 10-4 二元搜尋樹搜尋法二元搜尋樹搜尋法 10-5 10-5 雜湊搜尋法雜湊搜尋法 10-6 10-6 雜湊函數的碰撞問題雜湊函數的碰撞問題

10-1 10-1 搜尋的基礎搜尋的基礎 -- 說明說明 「搜尋」(「搜尋」( SearchingSearching )是在資料中找尋)是在資料中找尋特定的值,這個值稱為「鍵值」(特定的值,這個值稱為「鍵值」( KeyKey )。)。例如:在電話簿以姓名找尋朋友電話號碼,例如:在電話簿以姓名找尋朋友電話號碼,姓名就是鍵值,或在書局以書號的鍵值找姓名就是鍵值,或在書局以書號的鍵值找尋喜愛的書。尋喜愛的書。 搜尋的目的是為了確定資料中是否存在與搜尋的目的是為了確定資料中是否存在與鍵值相同的資料。鍵值相同的資料。

10-1 10-1 搜尋的基礎搜尋的基礎 -- 範例範例 搜尋的目的是為了確定資料中是否存在與鍵值相搜尋的目的是為了確定資料中是否存在與鍵值相同的資料。例如:學生連絡資料的記錄,如下圖同的資料。例如:學生連絡資料的記錄,如下圖所示:所示:

在上述記錄欄位的在上述記錄欄位的【【學號學號】】是鍵值,例如:搜尋是鍵值,例如:搜尋學號為學號為 S003S003 的學生,經搜尋找到學生郭富成,的學生,經搜尋找到學生郭富成,因為有此鍵值的學號,接著就可以找到學生姓名因為有此鍵值的學號,接著就可以找到學生姓名和電話號碼,然後與學生連絡。和電話號碼,然後與學生連絡。

10-1 10-1 搜尋的基礎搜尋的基礎 -- 種類種類 資料搜尋方法依照搜尋資料可以分成兩種,如下資料搜尋方法依照搜尋資料可以分成兩種,如下所示:所示: 沒有排序的資料:沒有排序的資料:針對沒有排序的資料執行搜尋,針對沒有排序的資料執行搜尋,需要從資料的第需要從資料的第 11 個元素開始比較,從頭到尾以個元素開始比較,從頭到尾以確認資料是否存在,例如:線性搜尋法。確認資料是否存在,例如:線性搜尋法。 已經排序的資料:已經排序的資料:搜尋不需要從頭開始一個個比搜尋不需要從頭開始一個個比較。例如:在電話簿找電話,相信沒有人是從電較。例如:在電話簿找電話,相信沒有人是從電話簿的第一頁開始找,而是直接從姓名出現的頁話簿的第一頁開始找,而是直接從姓名出現的頁數開始找,這是因為電話簿已經依照姓名排序好。數開始找,這是因為電話簿已經依照姓名排序好。例如:二元搜尋法和插補搜尋法。例如:二元搜尋法和插補搜尋法。

10-2 10-2 循序搜尋法 循序搜尋法 – – 未排序資料未排序資料(( 說明說明 ))

「循序搜尋法」(「循序搜尋法」( Sequential SearchSequential Search ))是從循序結構的第是從循序結構的第 11 個元素開始走訪整個個元素開始走訪整個結構,以陣列來說,就是陣列走訪,從頭結構,以陣列來說,就是陣列走訪,從頭開始一個一個比較元素是否是搜尋值,因開始一個一個比較元素是否是搜尋值,因為需要走訪整個陣列,陣列資料是否已經為需要走訪整個陣列,陣列資料是否已經排序就沒有什麼關係。排序就沒有什麼關係。

10-2 10-2 循序搜尋法 循序搜尋法 – – 未排序資料未排序資料(( 範例範例 ))

例如:在整數陣列例如:在整數陣列 data[]data[] 搜尋整數搜尋整數 9090 的鍵值,的鍵值,程式需要從陣列索引值程式需要從陣列索引值 00 開始比較,在經過索引開始比較,在經過索引值值 11 、、 22 和和 33 後,才在索引值後,才在索引值 44 找到整數找到整數 9090 ,,一共比較一共比較 55 次。次。

同理,如果搜尋整數同理,如果搜尋整數 44 的鍵值,需要從索引值的鍵值,需要從索引值 00一直找到一直找到 1010 ,才能夠確定鍵值是否存在,結果,才能夠確定鍵值是否存在,結果比較比較 1111 次發現鍵值次發現鍵值 44 不存在。不存在。

10-2 10-2 循序搜尋法 循序搜尋法 – – 未排序資料未排序資料(( 執行效率執行效率 ))

如果元素個數為如果元素個數為 nn ,循序搜尋法的執行效,循序搜尋法的執行效率是與元素個數成正比的率是與元素個數成正比的 O(n)O(n) 。。

10-3 10-3 已排序資料的搜尋法已排序資料的搜尋法 10-3-1 10-3-1 二元搜尋法二元搜尋法 10-3-2 10-3-2 插補搜尋法插補搜尋法

10-3-1 10-3-1 二元搜尋法二元搜尋法 -- 說明說明 「二元搜尋法」(「二元搜尋法」( Binary SearchBinary Search )是一)是一種分割資料的搜尋方法,搜尋資料需要是種分割資料的搜尋方法,搜尋資料需要是已經排序好的資料。已經排序好的資料。 二元搜尋法的操作是先檢查排序資料的中二元搜尋法的操作是先檢查排序資料的中間元素,如果與鍵值相等就是找到,如果間元素,如果與鍵值相等就是找到,如果小於鍵值,表示資料位在前半段,否則位小於鍵值,表示資料位在前半段,否則位在後半段。然後繼續分割成二段資料重覆在後半段。然後繼續分割成二段資料重覆上述操作,直到找到或已經沒有資料可以上述操作,直到找到或已經沒有資料可以分割為止。分割為止。

10-3-1 10-3-1 二元搜尋法二元搜尋法 -- 方法方法 例如:陣列的上下範圍分別是例如:陣列的上下範圍分別是 lowlow和和 highhigh ,,中間元素的索引值是中間元素的索引值是 (low + high)/2(low + high)/2 。在。在執行二元搜尋時的比較,可以分成三種情執行二元搜尋時的比較,可以分成三種情況,如下所示:況,如下所示:

•搜尋鍵值小於陣列的中間元素:搜尋鍵值小於陣列的中間元素:鍵值在資料陣鍵值在資料陣列的前半部。列的前半部。•搜尋鍵值大於陣列的中間元素:搜尋鍵值大於陣列的中間元素:鍵值在資料陣鍵值在資料陣列的後半部。列的後半部。•搜尋鍵值等於陣列的中間元素:搜尋鍵值等於陣列的中間元素:找到搜尋的鍵找到搜尋的鍵值。值。

10-3-1 10-3-1 二元搜尋法二元搜尋法 -- 過程過程 11 在已經排序好的整數陣列在已經排序好的整數陣列 data[]data[] 找尋整數找尋整數 8181 的的鍵值,第一步和陣列中間元素索引值鍵值,第一步和陣列中間元素索引值 (0+10)/2 (0+10)/2

= 5= 5 的值的值 3333 比較,因為比較,因為 8181 大於大於 3333 ,所以搜尋,所以搜尋陣列的後半段,如下圖所示:陣列的後半段,如下圖所示:

10-3-1 10-3-1 二元搜尋法二元搜尋法 -- 過程過程 22 搜尋範圍已經縮小剩下後半段,中間元素搜尋範圍已經縮小剩下後半段,中間元素索引值索引值 (6+10)/2 = 8(6+10)/2 = 8 ,其值為,其值為 7474 。因為。因為

8181 仍然大於仍然大於 7474 ,所以繼續搜尋後半段,,所以繼續搜尋後半段,如下圖所示:如下圖所示:

再度計算中間元素索引值再度計算中間元素索引值 (9+10)/2 = 9(9+10)/2 = 9 ,,找到搜尋值找到搜尋值 8181 。。

10-3-1 10-3-1 二元搜尋法二元搜尋法 -- 搜尋過程搜尋過程 整個二元搜尋過程可以使用陣列索引值繪出執行整個二元搜尋過程可以使用陣列索引值繪出執行過程的二元搜尋樹,節點內容為陣列索引值,如過程的二元搜尋樹,節點內容為陣列索引值,如下圖所示:下圖所示:

10-3-1 10-3-1 二元搜尋法二元搜尋法 -- 執行效率執行效率 二元搜尋法的平均和最差的執行效率很容二元搜尋法的平均和最差的執行效率很容易算出,因為每次都分為二半,其執行效易算出,因為每次都分為二半,其執行效率為率為 O(Log n)O(Log n) 。。

10-3-2 10-3-2 插補搜尋法插補搜尋法 -- 說明說明 循序和二元搜尋法都不是在電話簿或百科循序和二元搜尋法都不是在電話簿或百科全書查閱資料的方法,因為我們通常是依全書查閱資料的方法,因為我們通常是依照姓名或分類直接翻至相關章節或頁碼的照姓名或分類直接翻至相關章節或頁碼的前後,然後才決定是從前端、中間或後端前後,然後才決定是從前端、中間或後端開始搜尋,這種搜尋法稱為「插補搜尋開始搜尋,這種搜尋法稱為「插補搜尋法」(法」( Interpolation SearchInterpolation Search )。)。

10-3-2 10-3-2 插補搜尋法插補搜尋法 -- 原理原理 插補搜尋法以資料分佈情況計算出可能位置的索插補搜尋法以資料分佈情況計算出可能位置的索引值,來縮小搜尋的範圍,而不像二元搜尋法固引值,來縮小搜尋的範圍,而不像二元搜尋法固定分割一半來縮小範圍。例如:一個直角三角形,定分割一半來縮小範圍。例如:一個直角三角形,如下圖所示:如下圖所示:

10-3-2 10-3-2 插補搜尋法插補搜尋法 -- 索引公式索引公式 將圖形標上座標,並且假設三角形是一個分佈平將圖形標上座標,並且假設三角形是一個分佈平均的資料,我們可以推導出插補搜尋法計算可能均的資料,我們可以推導出插補搜尋法計算可能位置的索引值公式,如下圖所示:位置的索引值公式,如下圖所示:

10-3-2 10-3-2 插補搜尋法插補搜尋法 -- 執行效率執行效率 插補搜尋法的執行效率是:插補搜尋法的執行效率是:

O(Log(Log n))O(Log(Log n)) 。。

10-4 10-4 二元搜尋樹搜尋法二元搜尋樹搜尋法 -- 二元搜二元搜尋樹尋樹 「二元搜尋樹」(「二元搜尋樹」( Binary Search TreeBinary Search Tree )除了)除了可以使用中序走訪來排序資料外,也可以進行資可以使用中序走訪來排序資料外,也可以進行資料搜尋。例如:一棵二元搜尋樹,如下圖所示:料搜尋。例如:一棵二元搜尋樹,如下圖所示:

10-4 10-4 二元搜尋樹搜尋法二元搜尋樹搜尋法 -- 搜尋方搜尋方法法 二元搜尋樹搜尋法在搜尋資料時,只需將二元搜尋樹搜尋法在搜尋資料時,只需將資料與根節點比較,此時有二種情況,如資料與根節點比較,此時有二種情況,如下所示:下所示:

•資料比較大:資料比較大:往右子樹繼續搜尋。往右子樹繼續搜尋。•資料比較小:資料比較小:往左子樹繼續搜尋。往左子樹繼續搜尋。

10-4 10-4 二元搜尋樹搜尋法二元搜尋樹搜尋法 --遞迴函遞迴函數數 不同於第不同於第 77 章的二元搜尋樹搜尋章的二元搜尋樹搜尋法,法, BSTreeSearch()BSTreeSearch() 函數是一個遞迴函數,如函數是一個遞迴函數,如下所示:下所示:

int BSTreeSearch(BSTree ptr, int d) {int BSTreeSearch(BSTree ptr, int d) { if ( ptr != NULL ) { /* if ( ptr != NULL ) { /* 終止條件 終止條件 **// if ( ptr->data == d ) /* if ( ptr->data == d ) /* 找到了 找到了 **// return 1;return 1; else if ( ptr->data > d ) /* else if ( ptr->data > d ) /* 往左子樹找 往左子樹找 **// return BSTreeSearch(ptr->left, d);return BSTreeSearch(ptr->left, d); else /* else /* 往右子樹找 往右子樹找 **// return BSTreeSearch(ptr->right, d);return BSTreeSearch(ptr->right, d); } else return 0; /* } else return 0; /* 沒有找到 沒有找到 **//}}

10-4 10-4 二元搜尋樹搜尋法二元搜尋樹搜尋法 -- 執行效執行效率率 二元樹搜尋法的效率如果不考慮建立二元二元樹搜尋法的效率如果不考慮建立二元搜尋樹的時間,其執行效率與二元搜尋法搜尋樹的時間,其執行效率與二元搜尋法相同是相同是 O(Log n)O(Log n) 。。

10-5 10-5 雜湊搜尋法雜湊搜尋法 10-5-1 10-5-1 雜湊搜尋法的基礎雜湊搜尋法的基礎 10-5-2 10-5-2 雜湊函數雜湊函數

10-5-1 10-5-1 雜湊搜尋法的基礎雜湊搜尋法的基礎 -- 說明說明 對於龐大資料的搜尋而言,搜尋效率的增對於龐大資料的搜尋而言,搜尋效率的增進仍然無法滿足實際的需求,在實作上,進仍然無法滿足實際的需求,在實作上,我們需要一種更好的搜尋方法,這就是我們需要一種更好的搜尋方法,這就是「雜湊搜尋法」(「雜湊搜尋法」( Hashing SearchHashing Search )。)。 雜湊搜尋法的原理是儘量減少搜尋範圍到雜湊搜尋法的原理是儘量減少搜尋範圍到只有一個,換句話說,搜尋操作只需檢查只有一個,換句話說,搜尋操作只需檢查一個位置,就可以回答找到或沒有找到。一個位置,就可以回答找到或沒有找到。

10-5-1 10-5-1 雜湊搜尋法的基礎雜湊搜尋法的基礎 -- 範例範例11

例如:一個結構陣列例如:一個結構陣列 data[]data[] 的編號欄位是鍵值,的編號欄位是鍵值,其範圍從其範圍從 11 到到 99 ,如果使用循序搜尋法搜尋鍵值,如果使用循序搜尋法搜尋鍵值77 的的【【張無忌張無忌】】記錄,一共需要經過記錄,一共需要經過 44 次比較才次比較才能找到,如下圖所示:能找到,如下圖所示:

10-5-1 10-5-1 雜湊搜尋法的基礎雜湊搜尋法的基礎 -- 範例範例22

陣列陣列 hashTable[]hashTable[] 是預先建立好的索引資料。搜是預先建立好的索引資料。搜尋鍵值只需檢查指標陣列索引值的內容是否為尋鍵值只需檢查指標陣列索引值的內容是否為 -1-1 ,,搜尋範圍縮小到只有搜尋範圍縮小到只有 11 個位置,這個指標陣列就個位置,這個指標陣列就是「雜湊表」(是「雜湊表」( Hash TablesHash Tables ),如下圖所示:),如下圖所示:

10-5-2 10-5-2 雜湊函數雜湊函數 -- 說明說明 雜湊搜尋法的資料搜尋是透過雜湊表來執行搜尋,雜湊搜尋法的資料搜尋是透過雜湊表來執行搜尋,所以雜湊搜尋法最主要的工作是建立「雜湊表」所以雜湊搜尋法最主要的工作是建立「雜湊表」(( Hashing TablesHashing Tables ),而建立雜湊表的方式則),而建立雜湊表的方式則是由使用的雜湊函數而定,雜湊函數是一種數學是由使用的雜湊函數而定,雜湊函數是一種數學運算,其目的是減少資料範圍,將搜尋鍵值轉換運算,其目的是減少資料範圍,將搜尋鍵值轉換成索引位置,如下圖所示:成索引位置,如下圖所示:

10-5-2 10-5-2 雜湊函數雜湊函數 --除法除法 (( 說明說明 ))

除法(除法( Division MethodDivision Method )) 除法的雜湊函數是將資料除以常數,然後除法的雜湊函數是將資料除以常數,然後使用餘數作為索引位置,其公式如下所示:使用餘數作為索引位置,其公式如下所示:

索引位置 索引位置 = = 鍵值 鍵值 mod Mmod M 上述上述 MM 是除數,可以取得鍵值除以此除數是除數,可以取得鍵值除以此除數的餘數。的餘數。

10-5-2 10-5-2 雜湊函數雜湊函數 --除法除法 (( 範例範例 )) 例如:搜尋的鍵值清單,如下所示:例如:搜尋的鍵值清單,如下所示:

11, 15, 49, 78, 53, 26, 2211, 15, 49, 78, 53, 26, 22 上述鍵值範圍是上述鍵值範圍是 11~7811~78 ,所以一共需要,所以一共需要

6868 個元素才能建立雜湊表,現在使用個元素才能建立雜湊表,現在使用 1010餘數運算的雜湊函數,其結果如下所示:餘數運算的雜湊函數,其結果如下所示:1, 5, 9, 8, 3, 6, 21, 5, 9, 8, 3, 6, 2

10-5-2 10-5-2 雜湊函數雜湊函數 --除法除法 (( 圖例圖例 )) 經過轉換後,只需值經過轉換後,只需值 1~91~9 的範圍就可以建的範圍就可以建立雜湊表,如下圖所示:立雜湊表,如下圖所示:

10-5-2 10-5-2 雜湊函數雜湊函數 -- 中中間平方法間平方法中間平方法(中間平方法( Mid-Square MethodMid-Square Method )) 中間平方法是將鍵值乘以自己或某個常數,中間平方法是將鍵值乘以自己或某個常數,然後取中間幾位數字做為索引位置。例如:然後取中間幾位數字做為索引位置。例如:取中間三位數的中間平方法,如下所示:取中間三位數的中間平方法,如下所示:

(136)2 = 21204 →120(136)2 = 21204 →120(2642)2 = 6980164 →016(2642)2 = 6980164 →016

上述中間平方法只取中間三個數字來作為上述中間平方法只取中間三個數字來作為雜湊表的索引位置。雜湊表的索引位置。

10-5-2 10-5-2 雜湊函數雜湊函數 -- 數位分析法數位分析法 11

數位分析法(數位分析法( Digit Analysis MethodDigit Analysis Method )) 數位分析法適用在數值鍵值的雜湊搜尋。例如:數位分析法適用在數值鍵值的雜湊搜尋。例如:電話號碼資料,如下所示:電話號碼資料,如下所示:

02-772-453102-772-453102-771-354702-771-354702-773-762402-773-762402-772-851302-772-851302-771-556502-771-5565

上述電話號碼資料如果作為雜湊表的索引位置,上述電話號碼資料如果作為雜湊表的索引位置,需要的記憶體空間將是一個天文數字。如果現在需要的記憶體空間將是一個天文數字。如果現在可用的記憶體空間只有可用的記憶體空間只有 10001000 個,我們需要找出個,我們需要找出一個縮小索引位置的方法。一個縮小索引位置的方法。

10-5-2 10-5-2 雜湊函數雜湊函數 -- 數位分析法數位分析法 22 電話號碼的區域號碼都相同,所以不用考慮,接電話號碼的區域號碼都相同,所以不用考慮,接著三個號碼的變化也不大,可以省略。最後四位著三個號碼的變化也不大,可以省略。最後四位數字只保留三位數,因為這幾支電話號碼中,最數字只保留三位數,因為這幾支電話號碼中,最後四碼的第二位數多半是後四碼的第二位數多半是 55 ,所以也將之省略,,所以也將之省略,最後得到的轉換規則,如下表所示:最後得到的轉換規則,如下表所示:

10-5-2 10-5-2 雜湊函數雜湊函數 --折疊法折疊法 11

折疊法(折疊法( Folding MethodFolding Method )) 折疊法是將鍵值分成幾個部分,除了最後折疊法是將鍵值分成幾個部分,除了最後一個部分外,其餘部分都是相同長度。例一個部分外,其餘部分都是相同長度。例如:將一個長整數如:將一個長整數 1423724012093314237240120933 分分成成 55 個部分,如下所示:個部分,如下所示:

10-5-2 10-5-2 雜湊函數雜湊函數 --折疊法折疊法 22 折疊方式有很多種,常用的方法,如下所折疊方式有很多種,常用的方法,如下所示:示:

•位移折疊法(位移折疊法( Shift FoldingShift Folding ):):在分成幾在分成幾個部分後,直接靠左或靠右相加後,就是索引個部分後,直接靠左或靠右相加後,就是索引位置,如下所示:位置,如下所示:

10-5-2 10-5-2 雜湊函數雜湊函數 --折疊法折疊法 33

•邊界折疊法(邊界折疊法( Folding at the Folding at the BoundariesBoundaries):):在分成幾個部分後,並不在分成幾個部分後,並不是分割邊界,而是將左邊邊界折起來後相加,是分割邊界,而是將左邊邊界折起來後相加,所以所以 P2P2和和 P4P4 是反轉資料,如下所示:是反轉資料,如下所示:

10-6 10-6 雜湊函數的碰撞問題雜湊函數的碰撞問題 10-6-1 10-6-1 線性探測法線性探測法 10-6-2 10-6-2 重雜湊法重雜湊法 10-6-3 10-6-3 鏈結法鏈結法

10-6 10-6 雜湊函數的碰撞問題雜湊函數的碰撞問題 -- 說明說明 雜湊函數是使用數學運算來處理鍵值,以雜湊函數是使用數學運算來處理鍵值,以便計算出雜湊表的索引位置,不過任何雜便計算出雜湊表的索引位置,不過任何雜湊函數都不能保證鍵值在執行運算後,得湊函數都不能保證鍵值在執行運算後,得到的索引位置是唯一。到的索引位置是唯一。

• 例如:數字例如:數字 1414、、 2424和和 3434除以除以 1010 的餘數都的餘數都是是 44 ,這種將數個鍵值轉換成同一個索引位置,這種將數個鍵值轉換成同一個索引位置的情況稱為「碰撞」(的情況稱為「碰撞」( CollisionsCollisions ),換句話),換句話說,在同一個索引位置,就不知道可以找尋到說,在同一個索引位置,就不知道可以找尋到哪一個鍵值?哪一個鍵值?

10-6 10-6 雜湊函數的碰撞問題雜湊函數的碰撞問題 --解決解決方法方法 如果雜湊函數產生碰撞問題,在建立雜湊如果雜湊函數產生碰撞問題,在建立雜湊表時就需要解決碰撞問題,以便雜湊搜尋表時就需要解決碰撞問題,以便雜湊搜尋法能夠找到正確的鍵值。常用的碰撞問題法能夠找到正確的鍵值。常用的碰撞問題解決方法,如下所示:解決方法,如下所示:

• 線性深測法(線性深測法( Linear ProbingLinear Probing )。)。• 重雜湊法(重雜湊法( RehashingRehashing ):):•鏈結法(鏈結法( ChainingChaining )。)。

10-6-1 10-6-1 線性探測法線性探測法 -- 原則原則 「線性探測法」(「線性探測法」( Linear ProbingLinear Probing )當碰撞情)當碰撞情形發生時,如果該索引位置已經有鍵值,就使用形發生時,如果該索引位置已經有鍵值,就使用下列原則來處理,如下所示:下列原則來處理,如下所示:

• 如果鍵值欲存放的索引位置已經有鍵值存在時,將鍵如果鍵值欲存放的索引位置已經有鍵值存在時,將鍵值儲存在下一個索引位置。值儲存在下一個索引位置。• 如果原位置的下一個索引位置仍然已有鍵值,再將鍵如果原位置的下一個索引位置仍然已有鍵值,再將鍵值儲存在下一個索引位置,重覆操作直到找到一個空值儲存在下一個索引位置,重覆操作直到找到一個空位置。位置。

上述碰撞問題的處理稱為線性探測法或「線性開上述碰撞問題的處理稱為線性探測法或「線性開放地址法」(放地址法」( Linear Open AddressingLinear Open Addressing )。)。

10-6-1 10-6-1 線性探測法線性探測法 -- 範例範例 例如:搜尋的鍵值清單,如下所示:例如:搜尋的鍵值清單,如下所示:

37, 25, 11, 29, 34, 46, 44, 3537, 25, 11, 29, 34, 46, 44, 35 雜湊函數是使用除法的餘數運算,如下所雜湊函數是使用除法的餘數運算,如下所示:示:

索引位置 索引位置 = = 鍵值 鍵值 mod 10mod 10

10-6-1 10-6-1 線性探測法線性探測法 --建立步驟建立步驟1,21,2

Step 1Step 1 :首先建立大小:首先建立大小 1010 的一維陣列雜湊表,的一維陣列雜湊表,大小是雜湊函數的除數大小是雜湊函數的除數 1010 ,並且將雜湊表的所,並且將雜湊表的所有元素都清除成有元素都清除成 -1-1 ,如下圖所示:,如下圖所示:

Step 2Step 2 :處理鍵值:處理鍵值 3737 ,經過雜湊函數計算後,,經過雜湊函數計算後,得到陣列索引值是得到陣列索引值是 37 mod 10 = 737 mod 10 = 7 ,所以把鍵,所以把鍵值值 3737 存入雜湊表的索引值存入雜湊表的索引值 77 ,如下圖所示:,如下圖所示:

10-6-1 10-6-1 線性探測法線性探測法 --建立步驟建立步驟3,43,4

Step 3Step 3 :接著處理鍵值:接著處理鍵值 2525 ,經計算得索引值,經計算得索引值25 mod 10 = 525 mod 10 = 5 ,所以將鍵值,所以將鍵值 2525 存入雜湊表索存入雜湊表索引值引值 55 ,如下圖所示:,如下圖所示:

Step 4Step 4 :重複操作執行鍵值::重複操作執行鍵值: 1111、、 2929、、 3434和和 4646 ,經雜湊函數得到索引值:,經雜湊函數得到索引值: 11 、、 99 、、 44 和和66 ,將鍵值存入雜湊表後,如下圖所示:,將鍵值存入雜湊表後,如下圖所示:

10-6-1 10-6-1 線性探測法線性探測法 --建立步驟建立步驟 55 Step 5Step 5 :接著處理鍵值:接著處理鍵值 4444 ,經雜湊函數計算得,經雜湊函數計算得到索引值為到索引值為 44 ,不過索引值,不過索引值 44 已經有元素存在,已經有元素存在,碰撞發生了。依前述原則,接著檢查索引值碰撞發生了。依前述原則,接著檢查索引值 55 ,,元素存在,繼續檢查索引值元素存在,繼續檢查索引值 66 仍然有元素存在,仍然有元素存在,重覆檢查直到索引值重覆檢查直到索引值 88 是空的,所以將鍵值是空的,所以將鍵值 4444存入雜湊表,如下圖所示:存入雜湊表,如下圖所示:

10-6-1 10-6-1 線性探測法線性探測法 --建立步驟建立步驟 66 Step 6Step 6 :最後處理鍵值:最後處理鍵值 3535 ,經計算得索引值,經計算得索引值 55 ,,碰撞又發生了,找到索引值碰撞又發生了,找到索引值 99 仍然沒有空的索引仍然沒有空的索引位置。但是在雜湊表還有索引值位置。但是在雜湊表還有索引值 00 、、 22 和和 33 是空是空的,可以使用技巧將雜湊表的頭尾連接起來,如的,可以使用技巧將雜湊表的頭尾連接起來,如下:下:

temp = (temp+1) %10temp = (temp+1) %10• 公式計算下一個索引位置。經運算可以把鍵值公式計算下一個索引位置。經運算可以把鍵值 3535 儲存儲存在索引值在索引值 00 ,完成雜湊表的建立,如下圖所示:,完成雜湊表的建立,如下圖所示:

10-6-1 10-6-1 線性探測法線性探測法 -- 雜湊搜尋法雜湊搜尋法 雜湊搜尋法是在雜湊表搜尋鍵值,一樣需要使用雜湊搜尋法是在雜湊表搜尋鍵值,一樣需要使用雜湊函數來計算出索引位置。例如:搜尋鍵值雜湊函數來計算出索引位置。例如:搜尋鍵值 3434 ,,首先使用雜湊函數計算出索引值為首先使用雜湊函數計算出索引值為 34 mod 10 34 mod 10

= 4= 4 ,經比較雜湊表索引值,經比較雜湊表索引值 44 ,找到此鍵值。,找到此鍵值。

10-6-1 10-6-1 線性探測法線性探測法 -- 標頭檔標頭檔01: /* 01: /* 程式範例程式範例 : Ch10-6-1.h */: Ch10-6-1.h */02: #define MAX_LEN 10 /* 02: #define MAX_LEN 10 /* 最大陣列尺寸 最大陣列尺寸 **//03: int hashTable[MAX_LEN];/* 03: int hashTable[MAX_LEN];/* 雜湊表宣告 雜湊表宣告 **//04: /* 04: /* 抽象資料型態的操作函數宣告 抽象資料型態的操作函數宣告 **//05: extern void createHashTable(int len, int 05: extern void createHashTable(int len, int

*array);*array);06: extern void printHashTable();06: extern void printHashTable();07: extern int lineHashSearch(int key);07: extern int lineHashSearch(int key);08: extern int hashFunc(int key);08: extern int hashFunc(int key);

10-6-1 10-6-1 線性探測法線性探測法 -- 執行效率執行效率 雜湊搜尋法的執行效率在不考慮建立雜湊雜湊搜尋法的執行效率在不考慮建立雜湊表的時間和沒有碰撞情形發生的理想情況表的時間和沒有碰撞情形發生的理想情況下,執行效率可以達到下,執行效率可以達到 O(1)O(1) 。。

10-6-2 10-6-2 重雜湊法重雜湊法 -- 問題問題 重雜湊法可以解決線性深測法儲存位置過於集中重雜湊法可以解決線性深測法儲存位置過於集中的問題,這是線性探測法解決碰撞問題時,造成的問題,這是線性探測法解決碰撞問題時,造成的特殊情況,可以看出索引值的特殊情況,可以看出索引值 44 儲存的鍵值可能儲存的鍵值可能是索引值是索引值 11 、、 22 和和 33 發生碰撞而儲存的鍵值,或發生碰撞而儲存的鍵值,或是雜湊函數運算結果是是雜湊函數運算結果是 44 。索引值。索引值 66 可能是由索可能是由索引值引值 55 和和 66 碰撞而決定。碰撞而決定。 這樣的結果將造成搜尋時,比較的次數快速的增這樣的結果將造成搜尋時,比較的次數快速的增加,而且這些鍵值連續的現象將愈演愈烈,因為加,而且這些鍵值連續的現象將愈演愈烈,因為碰撞的機會大幅增加,所以鍵值越連越多,這種碰撞的機會大幅增加,所以鍵值越連越多,這種情況稱為「叢聚現象」(情況稱為「叢聚現象」( ClusterCluster ),如下圖所),如下圖所示:示:

10-6-2 10-6-2 重雜湊法重雜湊法 -- 說明說明 重雜湊法是使用多個雜湊函數來建立雜湊重雜湊法是使用多個雜湊函數來建立雜湊表,當第表,當第 11 個函數產生碰撞時,就使用第個函數產生碰撞時,就使用第22 個雜湊函數,如果第個雜湊函數,如果第 22 個函數也產生碰個函數也產生碰撞時,就使用第撞時,就使用第 33 個雜湊函數,如此可以個雜湊函數,如此可以減少碰撞發生的機率,降低儲存位置過於減少碰撞發生的機率,降低儲存位置過於集中的問題。集中的問題。

10-6-2 10-6-2 重雜湊法重雜湊法 -- 範例範例 例如:使用和上一節相同的鍵值清單,如下所示:例如:使用和上一節相同的鍵值清單,如下所示:

37, 25, 11, 29, 34, 46, 44, 3537, 25, 11, 29, 34, 46, 44, 35 雜湊函數一共有三個,都是使用除法的不同餘數雜湊函數一共有三個,都是使用除法的不同餘數運算,如下所示:運算,如下所示:

(1) (1) 索引位置 索引位置 = = 鍵值 鍵值 mod 10mod 10(2) (2) 索引位置 索引位置 = = 鍵值 鍵值 mod 2mod 2(3) (3) 索引位置 索引位置 = = 鍵值 鍵值 mod 3mod 3 的線性探測法的線性探測法

換句話說,如果第換句話說,如果第 11 個雜湊函數發生碰撞時,就個雜湊函數發生碰撞時,就使用第使用第 22 個雜湊函數,如果第個雜湊函數,如果第 22 個雜湊函數發生個雜湊函數發生碰撞時,就使用第碰撞時,就使用第 33 個雜湊函數。個雜湊函數。

10-6-2 10-6-2 重雜湊法重雜湊法 --建立過程建立過程 重雜湊法使用雜湊函數計算索引位置的完重雜湊法使用雜湊函數計算索引位置的完整過程,如下表所示:整過程,如下表所示:

10-6-2 10-6-2 重雜湊法重雜湊法 -- 雜湊表雜湊表 完整雜湊表的內容,如下圖所示:完整雜湊表的內容,如下圖所示:

10-6-3 10-6-3 鏈結法鏈結法 -- 問題問題 雖然重雜湊法可以解決線性深測法儲存位雖然重雜湊法可以解決線性深測法儲存位置過於集中的問題,不過線性探測法的雜置過於集中的問題,不過線性探測法的雜湊搜尋仍然有兩個問題,如下所示:湊搜尋仍然有兩個問題,如下所示:

•擴充困難:擴充困難:如果雜湊表的儲存空間有如果雜湊表的儲存空間有 nn 個元素,個元素,在存入在存入 n+1n+1 個元素時,就會發生鍵值無法存個元素時,就會發生鍵值無法存入的問題。入的問題。•鍵值刪除問題:鍵值刪除問題:除非重建整個雜湊表,否則刪除非重建整個雜湊表,否則刪除有碰撞情況的鍵值,在雜湊搜尋時就有可能除有碰撞情況的鍵值,在雜湊搜尋時就有可能再也找不到。再也找不到。

10-6-3 10-6-3 鏈結法鏈結法 -- 說明說明 鏈結法是使用類似第鏈結法是使用類似第 8-2-28-2-2 節的圖形鄰接節的圖形鄰接串列表示法來建立雜湊表,這是使用一個串列表示法來建立雜湊表,這是使用一個結構陣列的指標,分別指向各鍵值的串列,結構陣列的指標,分別指向各鍵值的串列,如果有碰撞發生,只是將鍵值的節點插入如果有碰撞發生,只是將鍵值的節點插入串列,就可以解決線性探測法遇到的問題。串列,就可以解決線性探測法遇到的問題。

10-6-3 10-6-3 鏈結法鏈結法 -- 標頭檔標頭檔01: /* 01: /* 程式範例程式範例 : Ch10-6-3.h */: Ch10-6-3.h */02: #define MAX_LEN 10 /* 02: #define MAX_LEN 10 /* 最大陣列尺寸 最大陣列尺寸 **//03: struct Node { /* 03: struct Node { /* 節點結構宣告 節點結構宣告 **//04: int data; /* 04: int data; /* 鍵值 鍵值 **//05: struct Node *next; /* 05: struct Node *next; /* 指下一個節點的指標 指下一個節點的指標 **//06: };06: };07: typedef struct Node *Table; 07: typedef struct Node *Table; 08: struct Node hashTable[MAX_LEN]; 08: struct Node hashTable[MAX_LEN]; 09: /* 09: /* 抽象資料型態的操作函數宣告 抽象資料型態的操作函數宣告 **//10: extern void createHashTable(int len, int *array);10: extern void createHashTable(int len, int *array);11: extern void printHashTable();11: extern void printHashTable();12: extern int chainHashSearch(int key);12: extern int chainHashSearch(int key);13: extern int hashFunc(int key);13: extern int hashFunc(int key);

10-6-3 10-6-3 鏈結法鏈結法 -- 範例範例 例如:搜尋的鍵值清單,如下所示:例如:搜尋的鍵值清單,如下所示:

37, 25, 11, 29, 34, 46, 44, 3537, 25, 11, 29, 34, 46, 44, 35 雜湊函數是使用除法的餘數運算,如下所雜湊函數是使用除法的餘數運算,如下所示:示:

索引位置 索引位置 = = 鍵值 鍵值 mod 10mod 10

10-6-3 10-6-3 鏈結法鏈結法 -- 雜湊表雜湊表

10-6-3 10-6-3 鏈結法鏈結法 -- 雜湊搜尋雜湊搜尋 雜湊表各鍵值的搜尋次數(即比較次數),雜湊表各鍵值的搜尋次數(即比較次數),如下表所示:如下表所示: