一、相關(guān)定義
查找——查找就是根據(jù)給定的某個(gè)值,在查找表中確定一個(gè)其關(guān)鍵字等于給定值的數(shù)據(jù)元素(或記錄)。所有這些需要被查的數(shù)據(jù)所在的集合,它的統(tǒng)稱叫查找表。
查找表——是由同一類型的數(shù)據(jù)元素(或記錄)構(gòu)成的集合。
關(guān)鍵字——關(guān)鍵字是數(shù)據(jù)元素中某個(gè)數(shù)據(jù)項(xiàng)的值,又稱為鍵值,用它可以標(biāo)識(shí)一個(gè)數(shù)據(jù)元素。也可以標(biāo)識(shí)一個(gè)記錄的某個(gè)數(shù)據(jù)項(xiàng)(字段),稱為關(guān)鍵碼。若此關(guān)鍵字可以唯一標(biāo)識(shí)一個(gè)記錄,則稱此關(guān)鍵字為主關(guān)鍵字。主關(guān)鍵字所在的數(shù)據(jù)項(xiàng)稱為主關(guān)鍵碼。對(duì)于那些可以識(shí)別多個(gè)數(shù)據(jù)元素(或記錄)的關(guān)鍵字,我們稱為次關(guān)鍵字。
查找表按照操作方式來分為兩大種:靜態(tài)查找表和動(dòng)態(tài)查找表。
靜態(tài)查找表——只作查找操作的查找表。它的主要操作有:
(1)查詢某個(gè)“特定的”數(shù)據(jù)元素是否在查找表中。
(2)檢索某個(gè)“特定的”數(shù)據(jù)元素和各種屬性。
動(dòng)態(tài)查找表——在查找過程中同時(shí)插入查找表中不存在的數(shù)據(jù)元素,或者從查找表中刪除已經(jīng)存在的某個(gè)數(shù)據(jù)元素。動(dòng)態(tài)查找表的操作有兩個(gè):
(1)查找時(shí)插入數(shù)據(jù)元素。
(2)查找時(shí)刪除數(shù)據(jù)元素。
為了提高查找的效率,需要專門為查找操作設(shè)置數(shù)據(jù)結(jié)構(gòu),這種面向查找操作的數(shù)據(jù)結(jié)構(gòu)稱為查找結(jié)構(gòu)。從邏輯上來說,查找所基于的數(shù)據(jù)結(jié)構(gòu)是集合,集合中的記錄之間沒有本質(zhì)關(guān)系。可是要想獲得較高的查找性能,就不能不改變數(shù)據(jù)元素之間的關(guān)系,在存儲(chǔ)時(shí)可以將查找集合組織成表、樹等結(jié)構(gòu)。
二、順序表查找(時(shí)間復(fù)雜度為O(n))
順序查找,又叫線性查找,是最基本的查找技術(shù),它的查找過程是:從表中第一個(gè)(或最后一個(gè))記錄開始,逐個(gè)進(jìn)行記錄的關(guān)鍵字和給定值比較,若某個(gè)記錄的關(guān)鍵字和給定值相等,則查找成功;如果直到最后一個(gè)(或第一個(gè))記錄,其關(guān)鍵字和給定值比較都不等時(shí),則表中沒有所查的記錄,查找不成功。
優(yōu)缺點(diǎn):
順序查找是有很大缺點(diǎn)的,n很大時(shí),查找效率極為低下,不過優(yōu)點(diǎn)也是有的,這個(gè)算法非常簡(jiǎn)單,對(duì)靜態(tài)查找表的記錄沒有任何要求,在一些小型數(shù)據(jù)的查找時(shí),是可以適用的。
三、有序表查找(線性有序時(shí)的查找)
3.1折半查找
折半查找技術(shù),又叫做二分查找。它的前提是線性表中的記錄必須是關(guān)鍵碼有序(通常從小到大有序),線性表必須采用順序存儲(chǔ)。折半查找的基本思想是:在有序表中,取中間記錄作為比較對(duì)象,若給定值與中間記錄的關(guān)鍵字相等,則查找成功;若給定值小于中間記錄的關(guān)鍵字,則在中間記錄的左半?yún)^(qū)繼續(xù)查找;若給定值大于中間記錄的關(guān)鍵字,則在中間記錄的右半?yún)^(qū)繼續(xù)查找。不斷重復(fù)上述過程,直到查找成功,或所有查找區(qū)域無記錄,查找失敗為止。
例如:100以內(nèi)的正整數(shù)猜數(shù)
優(yōu)缺點(diǎn):
由于折半查找的前提條件是需要有序表順序存儲(chǔ),對(duì)于靜態(tài)查找表,一次排序后不再變化,這樣的算法已經(jīng)比較好了。但對(duì)于需要頻繁執(zhí)行插入和刪除操作的數(shù)據(jù)集來說,維護(hù)有序的排序會(huì)帶來不小的工作量,那就不建議使用。
3.2插值查找
插值查找是根據(jù)要查找的關(guān)鍵字key與查找表中最大最小記錄的關(guān)鍵字比較后的查找方法,其核心就在于插值的計(jì)算公式{key-a[low]}/{a[high]-a[low]}。
優(yōu)缺點(diǎn):
它和折半查找的時(shí)間復(fù)雜度一樣,但對(duì)于表長(zhǎng)較大,而關(guān)鍵字分布又比較均勻的查找表來說,插值查找算法的平均性能比折半查找要好很多。
3.3斐波那契查找(是一種有序查找)
斐波那契查找是一種有序查找,它是利用了黃金分割原理來實(shí)現(xiàn)的。
優(yōu)缺點(diǎn):
斐波那契查找的時(shí)間復(fù)雜度和折半查找、插值查找一樣,但就平均性能來說,斐波那契查找要優(yōu)于折半查找。
四、線性索引查找
索引就是把一個(gè)關(guān)鍵字與它對(duì)應(yīng)的記錄相關(guān)聯(lián)的過程,一個(gè)索引由若干個(gè)索引項(xiàng)構(gòu)成,每個(gè)索引項(xiàng)至少應(yīng)包含關(guān)鍵字和其對(duì)應(yīng)的記錄在存儲(chǔ)器中的位置等信息。索引技術(shù)是組織大型數(shù)據(jù)庫(kù)以及磁盤文件的一項(xiàng)重要技術(shù)。
索引按照結(jié)構(gòu)可以分為線性索引、樹形索引和多級(jí)索引。此處只介紹線性索引。所謂線性索引就是將索引項(xiàng)集合組織為線性結(jié)構(gòu),也稱為索引表。重點(diǎn)介紹三種線性索引:稠密索引、分塊索引和倒排索引。
4.1稠密索引
稠密索引是指在線性索引中,將數(shù)據(jù)集中的每一個(gè)記錄對(duì)應(yīng)一個(gè)索引項(xiàng),如圖所示:
對(duì)于稠密索引這個(gè)索引表來說,索引項(xiàng)是一定按照關(guān)鍵碼有序的排列。索引項(xiàng)有序也就意味著,我們要查找關(guān)鍵字時(shí),可以用折半、插值、斐波那契等有序查找算法,大大提高了效率。
優(yōu)缺點(diǎn):
如果數(shù)據(jù)集非常大,比如上億,那也就意味著索引也得同樣的數(shù)據(jù)集長(zhǎng)度規(guī)模,對(duì)于內(nèi)存有限的計(jì)算機(jī)來說,可能就需要反復(fù)去訪問磁盤,查找性能反而大大下降了。
4.2分塊索引
稠密索引由于索引項(xiàng)與數(shù)據(jù)集的記錄個(gè)數(shù)相同,所以空間代價(jià)很大。為了減少索引項(xiàng)的個(gè)數(shù),可以對(duì)數(shù)據(jù)集進(jìn)行分塊,使其分塊有序,然后再對(duì)每一塊建立一個(gè)索引項(xiàng),從而減少索引項(xiàng)的個(gè)數(shù)。
分塊有序,是把數(shù)據(jù)集的記錄分成了若干塊,并且這些塊滿足兩個(gè)條件:
(1)塊內(nèi)無序,即每一塊內(nèi)的記錄不要求有序。當(dāng)然,如果能讓塊內(nèi)有序,對(duì)查找來說更加理想,不過這就需要付出大量時(shí)間和空間的代價(jià),因此通常不要求塊內(nèi)有序。
(2)塊間有序,例如,要求第二塊所有記錄的關(guān)鍵字均要大于第一塊中所有記錄的關(guān)鍵字,第三塊的所有記錄的關(guān)鍵字均要大于第二塊的所有記錄的關(guān)鍵字.......因?yàn)橹挥袎K間有序,才有可能給查找?guī)硇省?/p>
對(duì)于分塊有序的數(shù)據(jù)集,將每塊對(duì)應(yīng)一個(gè)索引項(xiàng),這種索引方法叫做分塊索引。如圖所示:此分塊索引的索引項(xiàng)結(jié)構(gòu)分為三個(gè)數(shù)據(jù)項(xiàng)。
(1)最大關(guān)鍵碼——它存儲(chǔ)每一塊中的最大關(guān)鍵字,這樣的好處在于可以使得在它之后的下一塊中的最小關(guān)鍵字也能比這一塊最大的關(guān)鍵字要大。
(2)存儲(chǔ)了塊中記錄的個(gè)數(shù),以便于循環(huán)時(shí)使用。
(3)用于指向塊首數(shù)據(jù)元素的指針,便于開始對(duì)這一塊中記錄進(jìn)行遍歷。
在分塊索引表中查找,就是分兩步進(jìn)行:
1.在分塊索引表中查找要查關(guān)鍵字所在的塊。由于分塊索引表是塊間有序的,因此很容易利用折半、插值等算法得到結(jié)果。
2.根據(jù)塊首指針找到相應(yīng)的塊,并在塊中順序查找關(guān)鍵碼。因?yàn)閴K中可以是無序的,因此只能順序查找。
優(yōu)缺點(diǎn):
分塊索引的效率比之順序查找的O(n)是高了不少,不過顯然它與折半查找相比還有不小的差距。因此在確定所在塊的過程中,由于塊間有序,所以可以應(yīng)用折半、插值等手段來提高效率。總的來說,分塊索引在兼顧了對(duì)細(xì)分塊不需要有序的情況下,大大增加了整體查找的速度,所以普遍被用于數(shù)據(jù)庫(kù)表查找等技術(shù)的應(yīng)用中。
4.3倒排索引
例如:
1.Books and friends should be few but good.
2.A good book is a good friend.
在這里,這個(gè)單詞表就是索引表,索引項(xiàng)的通用結(jié)構(gòu)是:
1.次關(guān)鍵碼,例如上面的“英文單詞”。
2.記錄號(hào)表,例如上面的“文章編號(hào)”。
其中記錄號(hào)表存儲(chǔ)具有相同次關(guān)鍵字的所有記錄的記錄號(hào)(可以是指向記錄的指針或者是該記錄的主關(guān)鍵字)。這樣的索引方法就是倒排索引。
優(yōu)缺點(diǎn):
倒排索引的優(yōu)點(diǎn)顯然就是查找記錄非常快,基本等于生成索引表后,查找時(shí)都不用去讀取記錄,就可以得到結(jié)果。但它的缺點(diǎn)是這個(gè)記錄號(hào)不定長(zhǎng),維護(hù)比較困難。
五、二叉排序樹(動(dòng)態(tài)查找表)
對(duì)集合{62,88,58,47,35,73,51,99,37,93}做查找,考慮用二叉樹結(jié)構(gòu),而且是排好序的二叉樹來創(chuàng)建,如圖所示:
二叉排序樹又稱為二叉查找樹。它或者是一顆空樹,或者是具有下列性質(zhì)的二叉樹:
(1)若它的左子樹不為空,則左子樹上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值。
(2)若它的右子樹不為空,則右子樹上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值。
(3)它的左、右子樹也分別為二叉排序樹。
優(yōu)缺點(diǎn):
構(gòu)造一棵二叉排序樹的目的,其實(shí)并不是為了排序,而是為了提高查找和插入刪除關(guān)鍵字的速度。不管如何,在一個(gè)有序數(shù)據(jù)集上的查找,速度總要快于無序的數(shù)據(jù)集的,而二叉排序樹這種非線性的結(jié)構(gòu),也有利于插入和刪除的實(shí)現(xiàn)。
二叉排序樹總結(jié):
二叉排序樹是以鏈接的方式存儲(chǔ),保持了鏈接存儲(chǔ)結(jié)構(gòu)在執(zhí)行插入或刪除操作時(shí)不用移動(dòng)元素的優(yōu)點(diǎn),只要找到合適的插入和刪除位置后,僅需修改鏈接指針即可。插入刪除的時(shí)間性能比較好。而對(duì)于二叉排序樹的查找,走的就是從根結(jié)點(diǎn)到要查找的結(jié)點(diǎn)的路徑,其比較次數(shù)等于給定值的結(jié)點(diǎn)在二叉排序樹的層數(shù)。極端情況,最少為1次,即根結(jié)點(diǎn)就是要找的結(jié)點(diǎn),最多也不會(huì)超過數(shù)的深度。也就是說,二叉排序樹的查找性能取決于二叉排序樹的形狀。
六、平衡二叉樹(AVL樹)
平衡二叉樹是一種二叉排序樹,其中左子樹和右子樹的高度差至多等于1。將二叉樹上結(jié)點(diǎn)的左子樹深度減去右子樹深度的值稱為平衡因子BF,那么平衡二叉樹上所有結(jié)點(diǎn)的平衡因子只可能是-1,0和1。只要二叉樹上有一個(gè)結(jié)點(diǎn)的平衡因子的絕對(duì)值大于1,則該二叉樹就是不平衡的。
距離插入結(jié)點(diǎn)最近的,且平衡因子的絕對(duì)值大于1的結(jié)點(diǎn)為根的子樹,稱為最小不平衡子樹。如圖所示:
平衡二叉樹的實(shí)現(xiàn)原理:
平衡二叉樹構(gòu)建的基本思想就是在構(gòu)建二叉排序樹的過程中,每當(dāng)插入一個(gè)結(jié)點(diǎn)時(shí),先檢查是否因插入而破壞了樹的平衡性,若是,則找出最小不平衡子樹。在保持二叉排序樹特性的前提下,調(diào)整最小不平衡子樹中各結(jié)點(diǎn)之間的鏈接關(guān)系,進(jìn)行相應(yīng)的旋轉(zhuǎn),使之成為新的平衡子樹。(BF為正右旋,BF為負(fù)左旋)
平衡二叉樹總結(jié):
如果需要查找的集合本身沒有順序,在頻繁查找的同時(shí)也需要經(jīng)常的插入和刪除操作,顯然我們需要構(gòu)建一棵二叉排序樹,但是不平衡的二叉排序樹,查找效率是非常低的,因此需要在構(gòu)建時(shí),就讓這棵二叉排序樹是平衡二叉樹,此時(shí)時(shí)間復(fù)雜度和有序表查找一樣。
七、多路查找樹(B樹)
多路查找樹,其每一個(gè)結(jié)點(diǎn)的孩子數(shù)可以多于兩個(gè),且每一個(gè)結(jié)點(diǎn)處可以存儲(chǔ)多個(gè)元素。由于它是查找樹,所有元素之間存在某種特定的排序關(guān)系。
7.1 2-3樹
2-3樹是這樣一棵多路查找樹:其中的每一個(gè)結(jié)點(diǎn)都具有兩個(gè)孩子(稱之為2結(jié)點(diǎn))或三個(gè)孩子(稱之為3結(jié)點(diǎn))。
一個(gè)2結(jié)點(diǎn)包含一個(gè)元素和兩個(gè)孩子(或沒有孩子),且與二叉排序樹類似,左子樹包含的元素小于該元素,右子樹包含的元素大于該元素。不過,與二叉排序樹不一樣的是,這個(gè)2結(jié)點(diǎn)要么沒有孩子,要么就有兩個(gè)孩子,不能只有一個(gè)孩子。
一個(gè)3結(jié)點(diǎn)包含一小一大兩個(gè)元素和三個(gè)孩子(或沒有孩子),一個(gè)3結(jié)點(diǎn)要么沒有孩子,要么具有3個(gè)孩子。如果某個(gè)3結(jié)點(diǎn)有孩子的話,左子樹包含小于較小元素的元素,右子樹包含大于較大元素的元素,中間子樹包含介于兩元素之間的元素。
并且2-3樹中所有的葉子都在同一層次上。如圖所示:是一個(gè)有效的2-3樹。
2-3樹小結(jié):
2-3樹復(fù)雜的地方就是新結(jié)點(diǎn)的插入和已有結(jié)點(diǎn)的刪除。畢竟,每個(gè)結(jié)點(diǎn)可能是2結(jié)點(diǎn)也可能是3結(jié)點(diǎn),要保證所有葉子都在同一層次,是需要進(jìn)行復(fù)雜操作的。
7.2 2-3-4樹
2-3-4樹是在2-3樹的基礎(chǔ)上增加了4結(jié)點(diǎn)的使用。一個(gè)4結(jié)點(diǎn)包含大中小三個(gè)元素和四個(gè)孩子(或沒有孩子),一個(gè)4結(jié)點(diǎn)要么沒有孩子,要么具有4個(gè)孩子。如果某個(gè)結(jié)點(diǎn)有孩子的話,左子樹包含小于最小元素的元素;第二子樹包含大于最小元素,小于第二元素的元素;第三子樹包含大于第二元素,小于最大元素的元素;右子樹包含大于最大元素的元素。構(gòu)建數(shù)組為{7,1,2,5,6,9,8,4,3}的2-3-4樹的過程,如圖所示:
7.3 B樹
B樹是一種平衡的多路查找樹,2-3樹和2-3-4樹都是B樹的特例。結(jié)點(diǎn)最大的孩子數(shù)目稱為B樹的階,因此,2-3樹是3階B樹,2-3-4樹是4階B樹。
一個(gè)m階的B樹具有如下屬性:
(1)如果根結(jié)點(diǎn)不是葉節(jié)點(diǎn),則其至少有兩棵子樹。
(2)每一個(gè)非根的分支結(jié)點(diǎn)都有k-1個(gè)元素和k個(gè)孩子,其中m/2<=k<=m。每一個(gè)葉子結(jié)點(diǎn)n都有k-1個(gè)元素,其中m/2<=k<=m。
(3)所有葉子結(jié)點(diǎn)都位于同一層次。
(4)每個(gè)結(jié)點(diǎn)中的元素從小到大排列,結(jié)點(diǎn)當(dāng)中k-1個(gè)元素正好是k個(gè)孩子包含的元素的值域分劃。
(5)所有分支結(jié)點(diǎn)包含下列信息數(shù)據(jù)(n,A0,K1,A1,K2,A2,...Kn,An),其中:Ki(i=1,2,...n)為關(guān)鍵字,且Ki<Ki+1(i=1,2,...n-1);Ai(i=0,2,...n)為指向子樹根結(jié)點(diǎn)的指針,且指針Ai-1所指子樹中所有結(jié)點(diǎn)的關(guān)鍵字均小于Ki(i=1,2,...n),An所指子樹中所有結(jié)點(diǎn)的關(guān)鍵字均大于Kn,n([m/2]-1<=n<=m-1)為關(guān)鍵字的個(gè)數(shù)(或n+1為子樹的個(gè)數(shù))。
將下圖中的2-3-4樹轉(zhuǎn)成B樹示意圖如下:左側(cè)灰色方塊表示當(dāng)前結(jié)點(diǎn)的元素個(gè)數(shù)。
B樹小結(jié):
在B樹上查找的過程是一個(gè)順時(shí)針查找結(jié)點(diǎn)和在結(jié)點(diǎn)中查找關(guān)鍵字的交叉過程。由于B樹每結(jié)點(diǎn)可以具有比二叉樹多得多的元素,所以與二叉樹的操作不同,它們減少了必須訪問結(jié)點(diǎn)和數(shù)據(jù)塊的數(shù)量,從而提高了性能。可以說,B樹的數(shù)據(jù)結(jié)構(gòu)就是為內(nèi)外存的數(shù)據(jù)交互準(zhǔn)備的。
7.4 B+樹
B+樹是應(yīng)文件系統(tǒng)所需而出的一種B樹的變形樹。在B樹中,每一個(gè)元素在該樹中只出現(xiàn)一次,有可能在葉子結(jié)點(diǎn)上,也有可能在分支結(jié)點(diǎn)上。而在B+樹中,出現(xiàn)在分支結(jié)點(diǎn)中的元素會(huì)被當(dāng)做它們?cè)谠摲种ЫY(jié)點(diǎn)位置的中序后繼者(葉子結(jié)點(diǎn))中再次列出。另外,每一個(gè)葉子結(jié)點(diǎn)都會(huì)保存一個(gè)指向后一葉子結(jié)點(diǎn)的指針。如圖所示就是一棵B+樹,灰色關(guān)鍵字即是根結(jié)點(diǎn)中的關(guān)鍵字在葉子結(jié)點(diǎn)再次列出,并且所有葉子結(jié)點(diǎn)都鏈接在一起。
一棵m階的B+樹和m階的B樹的差異在于:
(1)有n棵子樹的結(jié)點(diǎn)中包含有n個(gè)關(guān)鍵字。
(2)所有的葉子結(jié)點(diǎn)包含全部關(guān)鍵字的信息,及指向含這些關(guān)鍵字記錄的指針,葉子結(jié)點(diǎn)本身依關(guān)鍵字的大小自小到大順序鏈接。
(3)所有分支結(jié)點(diǎn)可以看成是索引,結(jié)點(diǎn)中僅含有其子樹中的最大(或最小)關(guān)鍵字。
B+樹小結(jié):
B+樹的結(jié)構(gòu)特別適合帶有范圍的查找。B+樹的插入、刪除過程也都與B樹類似,只不過插入和刪除的元素都是在葉子結(jié)點(diǎn)上進(jìn)行而已。
八、散列表查找(哈希表)
散列技術(shù)是在記錄的存儲(chǔ)位置和它的關(guān)鍵字之間建立一個(gè)確定的對(duì)應(yīng)關(guān)系f,使得每個(gè)關(guān)鍵字key對(duì)應(yīng)一個(gè)存儲(chǔ)位置f(key)。對(duì)應(yīng)關(guān)系f稱為散列函數(shù),又稱為哈希函數(shù)。按這個(gè)思想,采用散列技術(shù)將記錄存儲(chǔ)在一塊聯(lián)系的存儲(chǔ)空間中,這塊連續(xù)存儲(chǔ)空間稱為散列表或哈希表。那么關(guān)鍵字對(duì)應(yīng)的記錄存儲(chǔ)位置稱為散列地址。
散列表查找步驟:
(1)在存儲(chǔ)時(shí),通過散列函數(shù)計(jì)算記錄的散列地址,并按此地址存儲(chǔ)該記錄。
(2)當(dāng)查找記錄時(shí),我們通過同樣的散列函數(shù)計(jì)算記錄的散列地址,按此散列地址訪問該記錄。
散列表查找小結(jié):
散列技術(shù)既是一種存儲(chǔ)方法也是一種查找方法。散列技術(shù)的記錄之間不存在什么邏輯關(guān)系,它只與關(guān)鍵字有關(guān)。因此,散列主要是面向查找的存儲(chǔ)結(jié)構(gòu)。
散列技術(shù)最適合的求解問題是查找與給定值相等的記錄。對(duì)于查找來說,簡(jiǎn)化了比較過程,效率就大大提高。但散列技術(shù)也有缺點(diǎn):
(1)比如那種同樣的關(guān)鍵字,它能對(duì)應(yīng)很多記錄的情況,卻不適合用散列技術(shù)。
(2)同樣散列表也不適合范圍查找。
九、散列函數(shù)的構(gòu)造方法
兩個(gè)關(guān)鍵字key1不等于key2,但是卻有f(key1)=f(key2),這種現(xiàn)象叫做沖突,并把key1和key2稱為這個(gè)散列函數(shù)的同義詞。
好的散列函數(shù)有兩個(gè)原則:
(1)計(jì)算簡(jiǎn)單:散列函數(shù)的計(jì)算時(shí)間不應(yīng)該超過其他查找技術(shù)與關(guān)鍵字比較的時(shí)間。
(2)散列地址分布均勻:盡量讓散列地址均勻的分布在存儲(chǔ)空間中,這樣可以保證存儲(chǔ)空間的有效利用,并減少為處理沖突而耗費(fèi)的時(shí)間。
9.1直接定址法
如果要統(tǒng)計(jì)80后出生年份的人口數(shù),如表所示,我們對(duì)出生年份這個(gè)關(guān)鍵字可以用年份減去1980來作為地址,此時(shí)f(key)=key-1980。
取關(guān)鍵字的某個(gè)線性函數(shù)值為散列地址,即:f(key)=a*key+b(a、b為常數(shù))
小結(jié):
這樣的散列函數(shù)優(yōu)點(diǎn)就是簡(jiǎn)單、均勻,也不會(huì)產(chǎn)生沖突,但問題是這需要事先知道關(guān)鍵字的分布情況,適合查找表較小且連續(xù)的情況。由于這樣的限制,在現(xiàn)實(shí)應(yīng)用中,此方法雖然簡(jiǎn)單,但卻不常用。
9.2數(shù)字分析法
如果關(guān)鍵字是位數(shù)較多的數(shù)字,例如電話號(hào),如表所示:
選擇后面的四位稱為散列地址就是不錯(cuò)的選擇。如果這樣的抽取工作還是容易產(chǎn)生沖突,還可以對(duì)抽取出來的數(shù)字再進(jìn)行反轉(zhuǎn)、右環(huán)移位、左環(huán)移位等方法。總的目的就是為了提供一個(gè)散列函數(shù),能夠合理的將關(guān)鍵字分配到散列表的各位置。
小結(jié):
抽取方法是使用關(guān)鍵字的一部分來計(jì)算散列存儲(chǔ)位置的方法,這在散列函數(shù)中是常常用到的手段。數(shù)字分析法通常適合處理關(guān)鍵字位數(shù)比較大的情況,如果事先知道關(guān)鍵字的分布且關(guān)鍵字的若干位分布較均勻,就可以考慮用這個(gè)方法。
9.3平均取中法
如果關(guān)鍵字是1234,那么它的平方就是1522756,再抽取中間的三位227用做散列地址。
小結(jié):
平均取中法比較適合于不知道關(guān)鍵字的分布、而位數(shù)又不是很大的情況。
9.4折疊法
折疊法是將關(guān)鍵字從左到右分割成位數(shù)相等的幾部分(注意最后一部分位數(shù)不夠時(shí)可以短些),然后將這幾部分疊加求和,并按散列表表長(zhǎng),取后幾位作為散列地址。
小結(jié):
折疊法事先不需要知道關(guān)鍵字的分布,適合關(guān)鍵字位數(shù)較多的情況。
9.5除留余數(shù)法
此方法為最常用的構(gòu)造散列函數(shù)方法。對(duì)于列表長(zhǎng)為m的散列函數(shù)公式為:f(key)=key mod p (p<=m)
mod是取模。事實(shí)上,這方法不僅可以對(duì)關(guān)鍵字直接取模,也可在折疊、平方取中后再取模。很顯然,本方法的關(guān)鍵就在于選擇合適的p,p如果選得不好就會(huì)容易產(chǎn)生同義詞。
9.6隨機(jī)數(shù)法
選擇一個(gè)隨機(jī)數(shù),取關(guān)鍵字的隨機(jī)函數(shù)值為它的散列地址。也就是f(key)=random(key)。此處的random是隨機(jī)函數(shù)。當(dāng)關(guān)鍵字的長(zhǎng)度不等時(shí),采用這個(gè)方法構(gòu)造散列函數(shù)是比較合適的。
十、處理散列沖突的方法
開放定址法、再散列函數(shù)法、鏈地址法、公共溢出區(qū)法
總結(jié)
二叉排序樹是動(dòng)態(tài)查找最重要的數(shù)據(jù)結(jié)構(gòu),它可以在兼顧查找性能的基礎(chǔ)上,讓插入和刪除也變得效率較高。不過為了達(dá)到最優(yōu)的狀態(tài),二叉排序樹最好是構(gòu)造成平衡的二叉樹才最佳。
B樹這種數(shù)據(jù)結(jié)構(gòu)是針對(duì)內(nèi)存與外存之間的存取而專門設(shè)計(jì)的。由于內(nèi)外存的查找性能更多取決于讀取的次數(shù),因此在設(shè)計(jì)中要考慮B樹的平衡和層次。
散列表是一種非常高效的查找數(shù)據(jù)結(jié)構(gòu),在原理上也與前面的查找不盡相同,它回避了關(guān)鍵字之間反復(fù)比較的繁瑣,而是直接一步到位查找結(jié)果。當(dāng)然,這也就帶來了記錄之間沒有任何關(guān)聯(lián)的弊端。應(yīng)該說,散列表對(duì)于那種性能要求高,記錄之間關(guān)系無要求的數(shù)據(jù)有非常好的適用性