笛卡爾樹


笛卡爾樹又稱笛卡兒樹,在數據結構中屬於二叉樹的一種。

笛卡爾樹結構由Vuillmin在解決范圍搜索的幾何數據結構問題時提出的,從數列中構造一棵笛卡爾樹可以線性時間完成,需要采用基於棧的算法來找到在該數列中的所有最近小數。由此可知,笛卡爾樹是一種特定的二叉樹數據結構,可由數列構造,在范圍最值查詢、范圍top k查詢(range top k queries)等問題上有廣泛應用。它具有堆的有序性,中序遍歷可以輸出原數列。

笛卡爾樹是一棵二叉樹,樹的每個節點有兩個值,一個為key,一個為value。光看key的話,笛卡爾樹是一棵二叉搜索樹,每個節點的左子樹的key都比它小,右子樹都比它大;光看value的話,笛卡爾樹有點類似堆,根節點的value是最小(或者最大)的,每個節點的value都比它的子樹要大。

構造笛卡爾樹的過程:

使用數據結構棧,棧中保存的始終是右鏈,即根結點、根結點的右兒子、根結點的右兒子的右兒子……組成的鏈
並且棧中從棧頂到棧底key依次減小


如果按照從后到前的順序判斷一個元素是否大於A[i],則每次插入的時間復雜度為O(k+1)
k為本次插入中移除的右鏈元素個數。因為每個元素最多進出右鏈各一次,所以整個過程的時間復雜度為O(N)。

從前往后遍歷A[i],
1.對於每一個A[i],從棧中找出(從棧頂往棧底遍歷,或者從數組后往前遍歷)第一個小於等於A[i]的元素
2.如果找到,i.parent為sta[k],同時sta[k].r=i,即i為sta[k]的右子樹,
3.如果棧中存在比A[i]大的元素 這些元素肯定是出棧了,這個問題最后的代碼統一表示。
同時,sta[k+1].parent=i; i.l=sta[k+1] 即sta[K+1]為i的左子樹
4.最后i入棧,比i大的A[i]都自動出棧了。


例子如下。
0 1 2 3 4 5 6 7 8  9      .....key
3 2 4 5 6 8 1 9 10 7      .....A,value

stack
0 1 2 3 4 5 6 7 8  ...num
0
1 2 3 4 5
6 7 8
6 9
最后sta[0].parent=-1;  為根節點 即 6 為根節點。

這里給出的是索引從0開始的[0,n-1]
如果題目給出的是[1,n],可以減一回到[0,n-1]上

代碼:

View Code
 1 #include <iostream>
 2 #include <queue>
 3 using namespace std;
 4 const int maxnum=10;
 5 
 6 int a[maxnum];
 7 struct node
 8 {
 9     int key;
10     int parent;
11     int l;
12     int r;
13 }tree[maxnum];
14 
15 
16 void Init()
17 {
18     int i;
19     for(i=0;i<maxnum;i++)
20         tree[i].parent=tree[i].l=tree[i].r=-1;  //初始化
21 }
22 
23 int Build_Tree()
24 {
25     int i,top,k;
26     int stack[maxnum];
27     top=-1;
28     for(i=0;i<maxnum;i++)
29     {
30         k=top;
31         while(k>=0 && a[stack[k]]>a[i])  //棧中比當前元素大的都出棧
32             k--;
33 
34         if(k!=-1)  //find it,棧中元素沒有完全出棧,當前元素為棧頂元素的右孩子
35         {
36             tree[i].parent=stack[k];
37             tree[stack[k]].r=i;
38         }
39         if(k<top)    //出棧的元素為當前元素的左孩子
40         {
41             tree[stack[k+1]].parent=i;
42             tree[i].l=stack[k+1];
43         }
44 
45         stack[++k]=i;//當前元素入棧
46         top=k;//top指向棧頂元素
47     }
48     tree[stack[0]].parent=-1;//遍歷完成后的棧頂元素就是根
49     return stack[0];
50 }
51 
52 void inorder(int node)
53 {
54    if(node!=-1)
55    {
56        inorder(tree[node].l);
57        cout<<tree[node].key<<endl;
58        inorder(tree[node].r);
59    }
60 }
61 
62 void levelorder(int node)
63 {
64     queue<int> q;
65     q.push(node);
66     while(!q.empty())
67     {
68         int k=q.front();
69         q.pop();
70         cout<<tree[k].key<<endl;
71         if(tree[k].l!=-1)
72             q.push(tree[k].l);
73         if(tree[k].r!=-1)
74             q.push(tree[k].r);
75     }
76 }
77 
78 int main()
79 {
80     int i;
81     Init();
82     for(i=0;i<maxnum;i++)
83     {
84         cin>>a[i];
85         tree[i].key=a[i];
86     }
87 
88     int root=Build_Tree();
89 
90     //inorder(root);
91     //levelorder(root);
92     return 0;
93 }
94 
95 /*
96 3 2 4 5 6 8 1 9 10 7
97 */

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM