12-1-2:
二叉搜尋樹:left.key<key<eight.key;
最小堆:key<left.key,key<right.key;
不能,使用堆排序的話,得O(nlgn)
12-1-3:
這個已經在第十章做過了,
使用棧的話,有點浪費,因為使用棧,parent就用不上了;
不使用棧的情況,就是使用parent回溯父結點,對於x,我們已經有了尋找x後繼得程式:TERR-SUCCSSOR,我們從最小節點開始調用TREE-SUCCESSOR即可
12-1-4:
這個也已經做過了,此處不重複
12-2-1:
c
12-2-2:
TREE-MINIMUM(x) if(x.left!=NULL) TREE-MINIMUM(x.left) else return xTREE-MAXIMUM(x) if(x.right!=NULL) TREE-MAXIMUM(x.right) else return x
12-2-3:
見二叉搜尋樹的c++代碼
12-2-4:
12-2-5:
如果x有兩個孩子,那麼它的後繼y必然是右子樹中的最小值,所以y必然沒有左孩子,否則其左孩子必然小於y大於x;
同理,x有兩個孩子,那麼其前驅必然沒有右孩子
12-3-1:
TREE-INSERT(T,z,x)//將z插入到以x為根的子樹中 if(T.root=NIL) T.root=z return if(x.key<z.key) if(x.right==NIL) x.right==z z.parent=x else TREE-INSERT(T,z,x.right) else if(x.left==NIL) x.left==z z.parent=x else TREE-INSERT(T,z,x.left)
12-3-3:
最壞情況下就是原來就是已序的,那麼構造的二叉搜尋樹就是一條鏈表,相當於進行插入排序,O(n^2)
最好的情況下,構造的是平衡的二叉樹,此時O(nlgn)
12-3-4:
不可交換
12-3-5:
//對於某一個節點,其右子樹上的節點都可以通過後繼得到TREE-SEARCH(T,k,begin,limit)//begin是起始點,limit是節點必須在limit的子樹中 current=begin next=current.p if(next==limit)//此時只有一個節點current,如果k不等於current.key,就沒有此節點 if(current.key==k) return current else return NIL while(next!=limit&&next.key<k) current=next next=next.p if(next.key==k) return next; //此時要麼current.key<k<next.key,要麼current==樹根,但是x必然在current的右子樹中 TREE-SEARCH(T,k,current.succ,next) //採用search的架構,但是,這裡必須增加一個參數begin_pro,它的後繼是begin //如果x稱為左孩子,那麼begin_pro的後繼是xTREE-INSERT(T,x,begin_pro,begin,limit) current=begin next=current.p if(next==limit)//此時只有一個節點current if(x.key<current.key)//x成為current的左孩子 x.p=current begin_pro.succ=x x.succ=current else//稱為右孩子 x.p=current x.succ=current.succ current.succ=x while(next!=limit&&next.key<k) current=next next=next.p if(next.key==k) return next; //此時要麼current.key<k<next.key,要麼current==樹根,但是x必然在current的右子樹中 TREE-INSERT(T,k,current,current.succ,next)//採用search的架構://對於某一個節點,其右子樹上的節點都可以通過後繼得到TREE-DELETE(T,k,begin_pro,begin,limit)//begin是起始點,limit是節點必須在limit的子樹中 current=begin next=current.p if(next==limit)//如果k存在,必然等於current.key x=current.succ begin_pro.succ=x x.p=current.p while(next!=limit&&next.key<k) current=next next=next.p if(next.key==k) return next; //此時要麼current.key<k<next.key,要麼current==樹根,但是x必然在current的右子樹中 TREE-DELETE(T,k,current,current.succ,next)
12-3-6:
刪除前驅而非後繼得情況與刪除後繼得情況基本相同,
公平策略:可以傳遞bool值,每次刪除後,都對bool值取反,當bool為真時刪除後繼,為假時刪除前驅;
或者使用rand()隨機播放
12-1:
這個題給出了三種策略解決關鍵字相同的問題,每種策略都值得學習
12-2:
構造好樹之後先序輸出:
//本著簡潔的原則,我們這裡只實現insert和preorder#include<iostream>#include<string>using namespace std;struct node{string str;node* p;node* left;node* right;node(string a="",node* b=NULL,node* c=NULL,node* d=NULL):str(a),p(b),left(c),right(d){}};class radix_tree{public:node* root;radix_tree(){root=new node;}//root表示0位串void insert(string s);void preorder(){_preorder(root);}private:void _preorder(node* x);};void radix_tree::insert(string s){node* y=NULL;node* x=root;for(int i=0;i<s.length();++i){if(s[i]==0){if(x->left==NULL){//此時x沒有左孩子,建立一個y=new node;x->left=y;y->p=x;}x=x->left;}else{if(x->right==NULL){y=new node;x->right=y;y->p=x;}x=x->right;}}//此時x即為s的插入點x->str=s;}void radix_tree::_preorder(node* x){if(x==NULL)return;if(x->str!="")cout<<x->str<<'\n';_preorder(x->left);_preorder(x->right);}