高級數據結構筆記摘要

  今天看了一下高級數據結構(主要是多維數組、廣義表、AVL樹、Splay樹)的內容,AVL樹的部分以前提過了就不講了,參見《紅黑樹和AVL樹》,挑了一些以爲重要或有意思的點寫在這裏,但願有錯誤的地方請不吝指正。html

  一、三元組存取稀疏矩陣(較多元素爲0),以及使用十字鏈表的方式來記錄稀疏矩陣ios

  二、注意廣義表中的head、tail兩個概念,以及深度、長度的概念;算法

         對於L = (x0,x1,…,xn), head(L) = x0,tail(L) = (x1,x2,…,xn)數組

  三、區分廣義表中的純表、再入表、循環表(深度爲∞)等概念數據結構

         純表:任何元素(原子/子表)只能出現1次(相似正常的樹結構)spa

         再入表:表中元素能夠重複出現(相似樹結構中兄弟結點能夠連線)code

         循環表:表中有迴路,深度爲無窮大htm

  四、線性表 <= 純表(樹)<= 再入表(兄弟結點之間有連線) <= 圖blog

  

 

 

 

  五、最佳BST樹的平均訪問長度,,其中pi表示內部節點的索引頻率,qi表示外部結點的索引頻率,pi/w或者qi/w表示對應的索引機率,要注意的是li + 1和li’之間的區別!其中li和li’都是路徑長度,在等機率條件下能夠獲得 ASL(n) = (2I +3n)/(2n+1),其中I是內部路徑長度總和,因此要求ASL最小的話儘量地I要小,此時也就是整棵樹要接近徹底二叉樹。注意此處的一個大前提是等機率索引。排序

 

  六、在不是等機率訪問的前提下構建最佳BST樹的算法依據是最佳BST樹的子樹仍然是最佳BST樹,因此有最優子結構,所以能夠採用動態規劃的算法進行求解。只要在小區間裏枚舉相應的根節點並取出最小的就能夠了。具體的例子:四個關鍵碼爲B、D、H、F,訪問頻率爲1,5,4,3;且5個外部結點的訪問頻率爲5,4,3,2,1。

  隨便寫了一個代碼僅供參考:

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #define N 100000000
 5 using namespace std;
 6 int n, p[105], q[105], dp[105][105];//p爲內部結點,q爲外部結點,dp[i][j]表示從i~j的代價最小的BST樹 
 7 int sum(int i, int j){
 8     int m = 0;
 9     for(int k = i; k <= j; k++)m += (p[k] + q[k]);
10     return (m + q[i - 1]); 
11 }
12 int main(){
13     cin >> n;
14     for(int i = 1; i <= n ;i++){
15         cin >> p[i];
16     } 
17     for(int i = 0; i <= n; i++){
18         cin >> q[i];
19     }
20     for(int i = 0; i <= n ;i++){
21         for(int j = 0; j <= n; j++){
22             dp[i][j] = N;
23         }
24     }
25     //讀入n個內部節點和n+1個外部結點的訪問頻率 
26     for(int i = 1; i <= n; i++)dp[i][i] = p[i] + q[i - 1] + q[i];//單節點代價 
27     for(int len = 2; len <= n ; len++){
28         for(int s = 1; s + len - 1 <= n; s++){
29             int e = s + len - 1;//dp[s][e]
30             printf("s = %d ,e = %d\n", s, e);
31             for(int root = s; root <= e; root++){//枚舉根節點 
32                 if(root > s && root < e)
33                     dp[s][e] = min(dp[s][e], dp[s][root - 1] + dp[root + 1][e] + sum(s,root - 1) +p[root]+
34                     sum(root + 1, e));
35                 else if(root == s){
36                     dp[s][e] = min(dp[s][e], dp[root + 1][e] + p[root] + q[root - 1] + sum(root + 1,e));
37                 }
38                 else{
39                     dp[s][e] = min(dp[s][e], dp[s][root - 1] + p[root] + q[root] + sum(s,root - 1));
40                 }
41             } 
42         }
43     }
44     return 0;
45 } 

  (原來還有插入代碼這種高級的操做,感謝平臺)

  七、Trie結構:改變關鍵碼劃分的方式,key一般是字符串,是一種有序樹。基本性質有:1)根節點不包含字符,2)除根節點外每個結點只包含一個字符,3)從根節點到某一結點的路徑上字符鏈接起來獲得該節點的字符串,4)每一個節點的子節點包含的字符串都不同,見下面的圖示:

 

 

  八、在Trie樹中查找結點的效率和樹中包含的結點數量沒有關係,只和待查找的那個字符串的長度有關,這和AVL樹不同,好比一個長度5的字符串「ababa」,在AVL中須要log2(26**5) = 23.5次比較,在trie只要5次比較,可是trie樹是不平衡的,好比t下單詞比z下的單詞多的多,且不利於檢索(26個分支)。應用場所:前綴匹配、詞頻統計、排序。

  九、因爲數據訪問的規則,大多數的數據並不會被訪問,因此有了伸展樹(一種自組織的數據結構),數據隨檢索而調整位置。是對BST的改進,可是不能保持AVL中的平衡條件。

  十、訪問一次結點x就把x展開,插入時把x移動到根節點,刪除時把x的父節點移動到根節點。仍是分爲單旋轉和雙旋轉(直接提高),通常來講,一字型旋轉不會改變樹的高度,可是之字形旋轉會把樹的高度減1,更加平衡。

  十一、伸展樹不能保證每次訪問都是有效率的,也就是訪問多是O(N)的,可是可以保證m次操做總共須要O(mlogN)的,也就是平均代價是O(logN);嚴格的證實要用到攤還分析的方法,設x爲一棵子樹的根,S(x)爲這棵樹的總共節點數,u(x) = log2(S(x)),當前Splay樹的勢能定義爲全部結點的u(x)之和,分別考慮zig/zag, zigzig/zagzag, zigzag/zagzig這六種操做,實際上考慮三個狀況就行,不難發現每次旋轉都是以c * (u(x’) – u(x)) + 1爲上界,並且只有單純的zig/zag纔會用到1這個值,其他狀況下c = 3就足夠了,因而一次splay能夠證實是O(log2n)的,m次Splay的總攤還代價是O(m*log2n + nlog2n)(後面是由勢能提供的)。

  關於splay樹的複雜度分析,參考文章:https://max.book118.com/html/2017/0623/117570994.shtm

相關文章
相關標籤/搜索