1. 程式人生 > >【復習筆記】數據結構-檢索

【復習筆記】數據結構-檢索

磁盤訪問 span 不同 數字分析 clas temp 分析法 區間 再次

性能用ASL(查找成功時的平均查找長度)來衡量

線性表檢索

順序檢索

  • 逐個比較
  • 優點:插入元素可以直接加在表尾
  • 缺點:檢索時間太長

二分檢索法

  • 條件:序列必須有序
  • 實現:
     1 template <class Type> int BinSearch (vector<Item<Type>*>& dataList, int length, Type k){
     2     int low=1, high=length, mid;
     3     while (low<=high) { //結束條件!!
     4         mid = (low+high)/2
    ; 5 if (k<dataList[mid]->getKey()) 6 high = mid-1; //右縮檢索區間 7 else if (k>dataList[mid]->getKey()) 8 low = mid+1; //左縮檢索區間 9 else return mid; //成功返回位置 10 } 11 return 0; 12 } //檢索失敗,返回0
  • 性能分析:最大檢索長度(完全二叉樹的高度):$log_2^{n+1}$;失敗的檢索長度$log_2^{n+1}$向上或向下取整;平均的檢索長度和最大檢索長度接近:$log_2^{n+1}-1$
  • 優點:快
  • 缺點:要排序,不易更新

分塊檢索

  • 思想:兩級檢索。將元素分為多塊,塊內的關鍵碼不一定有序,但塊間有序(前塊中最大關鍵碼<後塊中最小關鍵碼);索引表中包含每個塊最大的關鍵碼和起始位置,以及每個塊裏元素的個數。
  • 性能:查找長度是兩級檢索的查找長度總和
  • 優點:更新容易
  • 缺點:
    • 需要一個輔助索引表
    • 分塊需要排序
    • 元素分布不均勻、大量插入或刪除時性能下降

散列表檢索(HASH)

基本概念

  • 帶檢索的關鍵碼K
  • 散列函數h(K):關鍵碼K的存儲位置
  • 負載(裝填)因子:$α=\frac{n}{M}$(n,散列表中已有結點數;M,散列表空間大小)
  • 沖突:將不同關鍵碼映射到相同散列地址
  • 同義詞:發生沖突的兩個關鍵碼

各類方法

除余法

  • $h(x)=x mod M$
  • M值通常選擇質數,有利於均勻分布
  • 潛在缺點:連續的關鍵碼映射為連續的散列值,散列性能降低

乘余取整法

  • $h(x)=n*(A*key\% 1)$

平方取中法

  • 求關鍵碼的平方,再取其中的幾位或其組合作為散列地址
  • 最接近隨機化

數字分析法

  • 分析每一位上不同符號出現頻率,選取其中各種符號均勻分布的若幹位作為散列地址

基數轉換法

  • 把關鍵碼看成是另一進制上的數後,再把它轉換成原來進制上的數。取其中若幹位作為散列地址
  • 一般取大於原來基數的數作為轉換的基數,並且兩個基數要互素。

折疊法

  • 將關鍵碼分割為位數相同的幾部分,取這幾部分的疊加和(舍去進位)作為散列地址。
  • 兩種疊加方法:移位疊加(各部分以最後一位對齊);分界疊加(沿各部分的分界來回折疊,對齊相加)

沖突的解決方法

開散列方法


拉鏈法(適用於內存)

  • 思路:所有同義詞鏈接在同一鏈表,以拉鏈狀拉開。每個槽定義為一個鏈表的表頭。
  • 這時候α可以大於1,但一般還是取小於1
  • 優點:適合表長不確定的情況,增刪結點容易。
  • 缺點:如果散列表元素在磁盤裏,拉鏈法不適用。
    • 同義詞表中的元素元素在不同的磁盤頁中的話,檢索一個特定關鍵碼時將引起多次磁盤訪問,增加檢索時間

桶式散列(適合存儲於磁盤的散列表)

  • 思想:散列文件記錄分為若幹桶,每個桶包含幾個頁塊,每個頁塊有若幹記錄,各頁塊用指針鏈接。h(k)表示具有關鍵碼K的記錄所在桶號。
  • 性能:桶目錄表最多一次訪外,逐個檢查桶內頁塊,平均訪外次數為桶內頁塊數一半。修改、插入等需另1次訪外寫外存。

閉散列方法(開地址法)


基本聚集:堆積,散列地址不同的記錄,爭奪同一後繼散列地址,導致很長的探查序列,偽隨機探查和二次探查可以消除基本聚集

二級聚集:如果兩個關鍵碼散列到同一基地址還是得到同一探查序列。

  • 把發生沖突的關鍵碼存儲在散列表中另一個空地址內
  • $d_0=h(K)$為K的基地址
  • $d_i=d_0+p(K,i)$是後繼散列地址,p(K,i)是探查函數
  • 搜索空位時,若基地址結點已被占用,逐個尋找探查序列中的空閑位置。如果找遍了都沒有,說明列表滿了,報告溢出。

線性探查法

  • 思想:逐個逐個往後找……$p(K,i)=i$
  • 優點:所有的存儲位置都可以作為插入記錄的候選
  • 缺點:聚集
  • 改進:每次跳過c個槽而不是1個
    • 第i個槽是$(h(K)+ic)mod M$,探查函數是$p(K,i)=i*c$
    • 基位置相鄰點記錄不會進入同一個探查序列
    • 但相隔c的還是糾纏在一起

二次探查

  • 地址公式:$d_{2i-1}=(d+i^2)%M;d_{2i}=(d-i^2)%M$
  • 探查函數:$p(K,2i-1)=i*i;p(K,2i)=-i*i$
  • 基本聚集消失

偽隨機數序列探查

  • 探查函數$p(K,i)=perm[i-1]$
    • perm是一個長度為M-1的數組,一個值在[1,M-1]的隨機序列
  • 基本聚集消失

雙散列探查法

  • 思想:使用兩個散列函數$h_1$和$h_2$
  • 若在$h_1(K)=d$發生沖突,計算h_2(K)得到的探查序列為探查序列:$d_i=(d+i*h_2(key))%M$
    • $(d+h_2(K))\% M$
    • $(d+2h_2(K))\% M$
    • $(d+3h_2(K))\% M$…
  • 探查函數:$p(K,i)=i*h_2(K)$
  • $h_2(K)$必須與M互素(否則可能會發生同義詞地址的循環計算)
  • 優點:不易產生聚集
  • 缺點:計算量增大(也不是很大)

閉散列的算法設計

  • 插入
    • 找到基地址空間
    • 基地址空間不空,循環找下一個探查序列直到關鍵碼值相同或找到空位
  • 檢索
    • 基地址空間未被占用,檢索失敗,否則將在基地址中的值和K比較,相等則成功。
    • 否則查找探查序列循環。直到找到相等關鍵碼或未被占用的地址空間。
  • 刪除
    • 開散列可以隨意刪除
    • 閉散列只能作標記,不能真正刪除,除非之後再次分配空間。不然會影響檢索操作
      • 設置一特殊的標記位(墓碑):單元被占用\空單元\已刪除
      • 插入時遇到墓碑,要繼續沿著探查序列找到真正空位,為了防止插入兩個相同的關鍵碼
      • 效率分析:不依賴於n,與α有關。α小時性能高。$α\leq 0.5$時,大部分操作的分析預期代價都小於2。負載因子的臨界值是0.5,超過性能就會急劇下降。
      • 技術分享圖片

【復習筆記】數據結構-檢索