笛卡爾樹簡介(分類到treap裡面)
阿新 • • 發佈:2019-01-09
構造笛卡爾樹的過程:
使用資料結構棧,棧中儲存的始終是右鏈,即根結點、根結點的右兒子、根結點的右兒子的右兒子……組成的鏈
並且棧中從棧頂到棧底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]上。
#include <iostream> #include <queue> using namespace std; const int maxnum=10; int a[maxnum]; struct node { int key; int parent; int l; int r; }tree[maxnum]; void Init() { int i; for(i=0;i<maxnum;i++) tree[i].parent=tree[i].l=tree[i].r=-1; //初始化 } int Build_Tree() { int i,top,k; int stack[maxnum]; top=-1; for(i=0;i<maxnum;i++) { k=top; while(k>=0 && a[stack[k]]>a[i]) //棧中比當前元素大的都出棧 k--; if(k!=-1) //find it,棧中元素沒有完全出棧,當前元素為棧頂元素的右孩子 { tree[i].parent=stack[k]; tree[stack[k]].r=i; } if(k<top) //出棧的元素為當前元素的左孩子 { tree[stack[k+1]].parent=i; tree[i].l=stack[k+1]; } stack[++k]=i;//當前元素入棧 top=k;//top指向棧頂元素 } tree[stack[0]].parent=-1;//遍歷完成後的棧頂元素就是根 return stack[0]; } void inorder(int node) { if(node!=-1) { inorder(tree[node].l); cout<<tree[node].key<<endl; inorder(tree[node].r); } } void levelorder(int node) { queue<int> q; q.push(node); while(!q.empty()) { int k=q.front(); q.pop(); cout<<tree[k].key<<endl; if(tree[k].l!=-1) q.push(tree[k].l); if(tree[k].r!=-1) q.push(tree[k].r); } } int main() { int i; Init(); for(i=0;i<maxnum;i++) { cin>>a[i]; tree[i].key=a[i]; } int root=Build_Tree(); //inorder(root); //levelorder(root); return 0; } /* 3 2 4 5 6 8 1 9 10 7 */