大話數據結構6 - 查找

查找searching
查找:根據給定的某個值,在查找表中確定一個其關鍵字等於給定值的數據元素/記錄
查找表,查找集合:同一類型數據元素/記錄的集合
查找結構:專門爲查找操作設置的數據結構,表、樹、圖結構
查找結果:成功(給出整個記錄的信息,給出該記錄的位置),不成功(給出一個空記錄,給出一個空指針)
按操作方式分類:2類
1、靜態查找表:只作查找操作1.查詢某個“特定”數據元素是否存在,2.檢索某個“特定”數據元素及數據項信息
2、動態查找表:1.查找時插入數據元素,2.查找時刪除數據元素
注意:動態查找表,既要考慮插入、刪除操作的效率,又要考慮查找操作的效率

關鍵字,鍵值:是數據元素中某個數據項的,用它可以標識一個數據元素
關鍵碼:關鍵字所標識的數據元素的某個數據項
主關鍵字,主關鍵碼:主關鍵字,唯一標識一個數據元素;主關鍵碼,主關鍵字所在的數據項
次關鍵字,次關鍵碼:次關鍵字,不唯一標識;次關鍵碼,次關鍵字所在的數據項
注意:對不同記錄,主關鍵字均不相同
注意:理解“唯一標識”,“不唯一標識”的含義
這裏的“唯一”,指的是對同一字段中的值進行的判斷,如果是不同字段,相等、不相等,一般都沒有什麼實際的意義。“唯一標識”在同一字段中沒有重複值,“不唯一標識”在同一字段中有重複字段,如果所有字段都重複就是重複記錄。

順序表查找,有序表查找,線性索引查找,二叉排序樹,平衡二叉樹,多路查找樹,散列表、哈希表查找

一:靜態
1、順序表查找,順序表:線性表
從頭到尾、從尾到頭查找
優化:在查找方向的盡頭放置“哨兵”,判斷查找是否越界的小技巧
順序表存放規則:根據查找頻率,將經常要查找的記錄放在前面,不常用的記錄放在後邊
2、有序表查找,有序表:a.線性表,b.關鍵碼有序,c.順序存儲
按照分割點選擇方法的不同,介紹3種:折半查找,插值查找,斐波那契查找
查找表a,分割點mid,最低下標low=1、記錄首位,最高下標high=n、記錄末位
1.折半查找,二分查找,mid=(low+high)/2 = low+(high-low)*1/2
2.插值查找,插值公式=(key-a[low])/(a[high]-a[low]),mid=low+(high-low)*(key-a[low])/(a[high]-a[low]),適用:關鍵字分佈比較均勻的查找表
3.斐波那契查找,黃金分割,mid=low+F[k-1]-1,斐波那契數列:F[K]=F[K-1]+F[K-2]
3、線性索引查找,索引表:a.線性表,b.帶指針,c.有序

注意:a.索引是對於按先後順序存儲的海量數據,爲了加快查找速度而設計的一種查找結構,b.索引是根據原數據集新生成的一個數據集合
注意:索引技術被廣泛的用於文件檢索、數據庫、搜索引擎等技術領域
索引:把一個關鍵字與它對應的記錄相關聯的過程,一個索引由若干個索引項組成
索引項:至少包含關鍵字、對應記錄的位置(指針)等信息
按結構分類:線性索引,樹形索引,多級索引
這裏只介紹線性索引:3種,稠密、分塊、倒排
線性索引,索引表:將索引項集合組織成線性結構
1.稠密索引:是指在線性索引中,數據集中的每個記錄對應一個索引項
特點:記錄無序,索引表中的索引項(按關鍵字)有序
索引項包含2個數據項:a.關鍵字,b.指針
缺點:索引項個數與數據集中的記錄個數相同,空間代價大
2.分塊索引:把數據集的記錄按分塊有序的原則分成若干塊,每一塊對應一個索引項
特點:分塊有序:a.塊內無序,塊內記錄可以無序,b.塊間有序,塊與塊之間按關鍵字有序,例如,第一塊中的所有記錄都小於第二塊中的記錄等
索引項包含3個數據項:a.最大關鍵字,b.快中的記錄個數,c.指向塊首數據元素的指針
最佳情況:分塊數m=塊中記錄數t
3.倒排索引,最基礎的搜索技術,根據屬性(字段、次關鍵碼)的值來查找記錄,不是由記錄確定屬性值,而是由屬性值確定記錄的位置
索引項通用結構,包含2個數據項:a.次關鍵字,b.記錄號表:是指向該記錄的指針、是該記錄的主關鍵字
優點:查找記錄非常快
缺點:記錄表號不定長,維護(插入刪除等)比較困難

二:動態:既要考慮插入、刪除的效率(鏈式存儲),又要考慮查找的效率(有序)
注意:二叉排序樹、平衡二叉排序樹是動態查找最重要的數據結構,B樹是爲內外存的數據交互專門設計準備的數據結構
1、二叉排序樹,二叉查找樹,BST:空樹、左<根<右的二叉樹,中序遍歷的結果是一個從小到大的有序序列
注意:區別有序樹(各結點位置有次序、不能互換),二叉樹就是有序樹
算法:使用二叉鏈表,遞歸原理
查找操作,遞歸查找
插入操作,構建一個二叉排序樹
刪除操作,分2種情況:a.僅有左子樹/左葉子的結點或僅有右子樹/右葉子的結點,c.左右子樹/左右葉子都有的結點
注意:對於b情況更好的思路是,使用刪除結點p的前驅s1或後繼s2來替換該結點,然後再刪除s。其中前驅s1一定是左子樹中最右的葉子或最右的僅帶一個左葉子的子樹根,後繼s2一定是右子樹中最左的葉子或最左的僅帶一個右葉子的子樹根
注意:1.查找操作要在查找遍歷整個二叉樹後、確定沒有該元素、再插入,程序是:插入程序中調用查找函數,2.刪除操作是隻要找到該元素就可以執行、不用遍歷整個樹,程序是:a.可以在刪除程序中調用查找函數b.也可以在查找程序中調用刪除函數
總結:1.插入刪除性能取決於存儲結構,鏈式存儲,修改指針,2.查找性能取決於二叉排序樹的層數/深度:最好情況,深度與完全二叉樹相同(平衡狀態)、近似折半查找;最壞情況,斜樹(二叉樹深度等於結點個數)、等同順序查找
2、平衡二叉樹,AVL樹:a.是二叉排序樹,b.每個結點的左右子樹高度差至多等於1
注意:是一種高度平衡的二叉排序樹,高度平衡是指:1.要麼是空樹,2.要麼它的左右子樹都是平衡樹,且左右子樹的深度差的絕對值不超過1
平衡因子BF:二叉樹上結點的左子樹深度減去右子樹深度的值,即BF=左深度-右深度,BF=-1、0、1
注意:只要二叉樹上有一個結點的平衡因子的絕對值大於1,該二叉樹就不是平衡的
最小不平衡子樹:距離插入結點最近的,且平衡因子的絕對值大於1的結點爲根的子樹
構建AVL樹的思想:在構建二叉排序樹的過程中,每插入一個結點就檢查是否因新插入的結點而破壞了平衡性,若是,找出最小不平衡子樹,進行調整
注意:把不平衡消滅在最早時刻
調整思路:
①BF=正(0、1、2),以BF=1爲軸,右旋轉/順時針旋轉,得到(0、0、0)
②BF=負(0、-1、-2),以BF=-1爲軸,左旋轉/逆時針旋轉,得到(0、0、0)
③BF=一正一負(0、1、-2),先以BF=1爲軸右旋轉,得到(0、-1、-2),再②,得到(0、0、0)
④BF=一負一正(0、-1、2),先以BF=-1爲軸左旋轉,得到(0、1、2),再①,得到(0、0、0)
注意:0=0 1=0 -1
算法:使用二叉鏈表
①增加bf,存儲平衡因子
②右旋函數R_Rotate:(0、1、2),左旋函數L_Rotate:(0、-1、-2)
平衡函數RightBalance:左(0、-1、-2),右左(0、1、-2),平衡函數LeftBalance:右(0、1、2),左右(0、-1、2
④主函數
3、多路查找樹:a.每個結點的孩子數可以多於2個,且每個結點處可以存儲多個元素,b.所有元素之間存在某種特定的排序關係
注意:多路樹,打破了一個結點只存儲一個元素的限制
4種特殊形式:2-3樹、2-3-4樹、B樹、B+樹
注意:1.其中它們的插入、刪除操作比較複雜,2.所有葉子結點都在同一層次上
①2-3樹:2結點或3結點
②2-3-4樹:2結點或3結點或4結點
2結點:1個元素2個孩子,要麼沒有孩子要麼有2個孩子,不能只有一個孩子,左<右
3結點:2個元素3個孩子,要麼沒有孩子要麼有3個孩子,左<中<右
4結點:3個元素4個孩子,要麼沒有孩子要麼有4個孩子,左<左中<右中<右
③B樹:是平衡的多路查找樹,2-3、2-3-4是B樹的特例
B樹的階:結點最大的孩子數目,例如2-3樹是3階B樹、2-3-4樹是4階B樹
B樹的查找過程:指針查找結點+結點中查找關鍵字
注意:B樹的數據結構是爲內外存的數據交互專門設計準備的,適用於外查找的樹
注意:內外存的查找性能更多取決於讀取次數,所以設計要考慮B樹的平衡和層次
④B+樹:應文件系統所需而出現的一種B樹的變形,解決了所有元素遍歷等基本問題
適用:B+樹結構特別適合帶有範圍的查找
注意:前面所講的樹都是沒有重複值的,即每一個元素在該樹中只出現一次,而B+樹不同於之前所講的樹,在B+樹結點中的元素會在葉子中再次列出,即元素會重複出現

三:散列表、哈希表查找:靜態查找,散列主要是面向查找的存儲結構
不用比較,直接通過關鍵字key得到要查找記錄的存儲位置
散列技術:在記錄的存儲位置和它的關鍵字之間建立一個確定的對應關係f,使得每個關鍵字key對應一個存儲位置f(key),存儲位置=f(關鍵字)
散列函數、哈希(Hash)函數:f,注意:散列技術中最關鍵的是設計一個簡單、均勻、利用率高的散列函數
散列表、哈希表(Hash table):使用散列技術將記錄存儲在一塊連續的存儲空間中,該存儲空間稱爲散列表,動態數組
散列地址:記錄的存儲位置/地址
散列過程:存儲、查找
注意:散列技術既是存儲方法,也是查找方法
注意:與之前的數據結構(線性表、樹、圖)不同,散列技術的記錄之間不存在什麼邏輯關係
注意:與之前不同,之前都是通過不斷的比較查找出i,散列是通過公式計算出i,散列表查找非常高效
優缺點:散列表查找直接一步到位、非常高效,但弊端是記錄之間沒有任何關聯,所以對於查找性能要求高,且記錄之間關係無要求的數據非常使用
適合:查找與給定值相等的記錄,且是主關鍵字的查找
不適合:次關鍵字的查找,範圍查找,排序查找
衝突:關鍵字key1≠key2,但f(key1)=f(key2),其中key1、key2稱爲這個散列函數的同義詞
注意:衝突不能完全避免
1、構造散列函數:
原則:a.計算簡單,b.散列地址分佈均勻(保證存儲空間的有效利用,減少爲處理衝突而耗費的時間)
①直接定址法
取關鍵字的某個線性函數,f(key)=a*key+b;優點:簡單、均勻、不會產生衝突;適合:事先知道關鍵字的分佈,查找表較小且連續;不常用
②數字分析法
抽取,使用關鍵字的一部分來計算存儲位置;適合:事先知道關鍵字的分佈且關鍵字若干位的分佈較均勻,關鍵字位數較多
③平方取中法
先(關鍵字^2)再抽取中間位;適合:不知道關鍵字分佈,關鍵字位數較少
④摺疊法
適合:不知道關鍵字分佈,關鍵字位數較多
除留餘數法
散列表長m,f(key)=key MOD p,(p≦m),其中可以對關鍵字取模,也可以在摺疊、平方取中後再取模;缺點:p值取的不好,很容易有衝突、出現同義詞,取的好也不容易避免衝突;最常用
⑥隨機數法
f(key)=random(key);適合:關鍵字長度不等
注意:如何選擇以上方法,考慮因素:散列地址計算時間、散列表長度、關鍵字長度、關鍵字分佈、記錄查找頻率
2、處理散列衝突
注意:1、2、4都是衝突換址,3是鏈表
①開放定址法,探測法
一旦發生衝突,就尋找下一個空的散列地址;fi(key)=(f(key)+di) MOD m,di=1,2,...,m-1,單向尋找,線性探測法
堆積:本來不是同義詞卻需要爭奪一個地址的現象
改進,di=1^2,-1^2,2^2,-2^2,...,q^2,-q^2,(q≦m/2),雙向尋找,二次探測法
僞隨機數,隨機種子,di=random(di),隨機探測法
注意:只要散列表沒有被填滿,總能找到不發生衝突的地址
②再散列函數法
fi(key)=RHi(key),i=1,2,...,k,RHi是不同的散列函數,一旦發生衝突就換一個散列函數
優點:使得關鍵字不會產生聚集
缺點:增加了計算時間
③鏈地址法
有衝突的關鍵字存儲在一個單鏈表中,同義詞子表
優點:衝突較多時,不會找不到空地址
缺點:查找時可能需要遍歷單鏈表
④公共溢出區法
有衝突的關鍵字都放在公共溢出表,散列表=基本表+溢出表
查找:先通過散列函數得到散列地址在基本表中找,如果沒有,再到溢出表中順序找
適合:衝突較少的情況
3、散列表的查找
散列表的查找性能取決於:①關鍵字的分佈,②散列函數的選擇,③處理衝突的方法,④裝填因子α
裝填因子=記錄個數/散列表長度,α=n/m,通常將散列表的空間設置的比查找表/集合大,空間換時間
注意:不管n有多大,我們總能選擇一個合適的裝填因子,將平均查找長度限定在一個範圍之內

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章