演算法導論第12章–二叉搜尋樹

來源:互聯網
上載者:User

/*二叉搜尋樹是一棵二叉樹,之所以成為搜尋樹,是因為適用於搜尋,大部分與搜尋有關的演算法, *大都採用這一策略,包括B樹,也可以看做是對二叉搜尋樹的擴充 *二叉搜尋樹滿足: *設x為樹中一個結點,如果y是x左子樹的一個節點,那麼y.key<=x.key *如果y是x右子樹的一個結點,那麼y.key>=x.key *//*二叉搜尋樹中的結點結構: *關鍵字key,衛星資料data *parent--父結點,left-child--左孩子,right-child右孩子 */#include<iostream>template<typename Key,typename Value>struct _bst_node{Key key;Value data;_bst_node<Key,Value>* parent;_bst_node<Key,Value>* left_child;_bst_node<Key,Value>* right_child;_bst_node(Key a=Key(),Value b=Value(),_bst_node<Key,Value>* c=NULL,_bst_node<Key,Value>* d=NULL,_bst_node<Key,Value>* e=NULL):key(a),data(b),parent(c),left_child(d),right_child(e){ }};//因為二叉搜尋樹實際價值不大,所以此處為了代碼的簡潔,我們使用new和delete來管理記憶體template<typename Key,typename Value>class bst_tree{public:typedef _bst_node<Key,Value> bst_node;private:bst_node* root;public:bst_tree(bst_node* r=NULL):root(r){ }bst_node* getRoot() const{return root;}//樹的中序遍曆,第二個參數為函數指標,作用於每一個節點void inorder_tree_walk(bst_node* x/*,void(*)(bst_node*)*/);//尋找,在以x為根的樹中尋找關鍵字為k的結點bst_node* tree_search(bst_node* x,Key k);//插入一個節點void tree_insert(bst_node* x);//刪除一個節點void tree_delete(bst_node* x);private://以x為根的樹,最大關鍵字元素bst_node* tree_maximum(bst_node* x);//以x為根的樹,最小關鍵字元素bst_node* tree_minimum(bst_node* x);//中序遍曆中·,x的前驅bst_node* tree_predecessor(bst_node* x);//中序遍曆中,x的後繼bst_node* tree_successor(bst_node* x);//delete的輔助程式,用一棵以v為根的子樹替換以u為根的子樹(這裡主要用於u只有一個子結點v時)void aux_transplant(bst_node* u,bst_node* v);void visit(bst_node* x)const{std::cout<<x->key<<' ';}};//-------------------------------------------------------------------------------------/*中序遍曆,我們已經在有根樹中實現過了,這裡為了減少耦合性,我們使用遞迴版本,從而避免 *使用stack和queue */template<typename Key,typename Value>void bst_tree<Key,Value>::inorder_tree_walk(bst_node* x/*,void(*visit)(bst_node* )*/){if(x!=NULL){inorder_tree_walk(x->left_child);visit(x);inorder_tree_walk(x->right_child);}}//-----------------------------------------------------------------------------------------/*尋找,我們尋找的時候,很自然的使用遞迴版本,但是,迭代版本的效率明顯高於遞迴版本,這裡 *附加兩個版本的偽碼: *RECURSIVE-TREE-SEARCH(x,k) *  if x==NULL or k==x.key *     return x *  elseif k<x.key *     return RECURSIVE-TREE-SEARCH(x.left,k) *  else return RECURSIVE-TREE-SEARCH(x.right,k) *顯而易見:T(n)=O(1)+T(n/2)=>時間複雜度是O(lgn),其中lgn=高度h *ITERATIVE-TREE-SEARCH(x,k) *  while x!=NULL and k!=x.key *      if k<x.key *          x=x.left *      else x=x.right *  return x */template<typename Key,typename Value>typename bst_tree<Key,Value>::bst_node* bst_tree<Key,Value>::tree_search(bst_node* x,Key k){bst_node* x_copy=x;while(x_copy!=NULL && k!=x_copy->key){if(k<x_copy->key) x_copy=x_copy->left_child;else x_copy=x_copy->right_child;}return x_copy;}//--------------------------------------------------------------------------------------//返回最小關鍵字元素,即最左的葉結點,時間複雜度O(h)template<typename Key,typename Value>typename bst_tree<Key,Value>::bst_node* bst_tree<Key,Value>::tree_minimum(bst_node* x){bst_node* x_copy=x;while (x_copy->left_child!=NULL){x_copy=x_copy->left_child;}return x_copy;}//------------------------------------------------------------------------------------//返回最大關鍵字元素,即最右的葉結點,O(h)template<typename Key,typename Value>typename bst_tree<Key,Value>::bst_node* bst_tree<Key,Value>::tree_maximum(bst_node* x){bst_node* x_copy=x;while(x_copy->right_child!=NULL){x_copy=x_copy->right_child;}return x_copy;}//--------------------------------------------------------------------------------------/*返回中序遍曆時,x的後繼,其中二叉搜尋樹的結構允許我們不通過任何關鍵字的比較獲得O(h): *case1:如果x的右子樹非空,那麼後繼y是x右子樹的最小元素 *case2:如果x的右子樹為空白: *          case1’:如果x是父結點的左孩子,那麼x的後繼為父結點 *          case2’:如果x是父結點y的右孩子,那麼尋找這樣一個節點z,使x,y所在的子樹為z的左子樹 */template<typename Key,typename Value>typename bst_tree<Key,Value>::bst_node* bst_tree<Key,Value>::tree_successor(bst_node* x){bst_node* x_copy=x;//case1:if(x_copy->right_child!=NULL){return tree_minimum(x_copy->right_child);}//case2://case1':bst_node* y= x_copy->parent;//case2':while(y!=NULL && x_copy!=y->left_child){x_copy=y;y=y->parent;}return y;}//--------------------------------------------------------------------------------------------/*返回中序遍曆時,x的前驅:O(h) *case1:x有左子樹,那麼x的前驅是x左子樹的最大值; *case2:x無左子樹 *         case1’:x是其父結點y的右孩子,那麼前驅為y *         case2’:x是其父結點y的左孩子,尋找祖先z,使x,y所在子樹是z的右子樹 */template<typename Key,typename Value>typename bst_tree<Key,Value>::bst_node* bst_tree<Key,Value>::tree_predecessor(bst_node* x){bst_node* x_copy=x;//case1:if(x_copy->left_child!=NULL)return x_copy->left_child;//case2://case1':bst_node* y=x_copy->parent;//case2':while(y!=NULL and y->right_child!=x_copy){x_copy=y;y=y->parent;}return y;}//---------------------------------------------------------------------------------------//插入操作,被插入的位置總是葉結點,節點x的左孩子和右孩子都為空白O(h)template<typename Key,typename Value>void bst_tree<Key,Value>::tree_insert(bst_node* x){bst_node* y=NULL;bst_node* z=root;//當樹是空的時候:if(z==NULL){x->parent=NULL;root=x;return;}//當樹非空時,令y為z的父結點while(z!=NULL){y=z;if(x->key<z->key)z=z->left_child;elsez=z->right_child;}//此時,y為x的父結點,已確定x->parent=y;//確定x是y的左孩子還是右孩子if(x->key<y->key)y->left_child=x;elsey->right_child=x;}//--------------------------------------------------------------------------------------template<typename Key,typename Value>void bst_tree<Key,Value>::aux_transplant(bst_node* u,bst_node* v){if(u->parent==NULL){//u為rootroot=v;}else if(u==u->parent->left_child){//u是左孩子u->parent->left_child=v;}else{u->parent->right_child=v;}if(v!=NULL){v->parent=u->parent;}}//-------------------------------------------------------------------------------------/*刪除操作非常麻煩,刪除x: *case1:如果x是葉結點,直接刪除,並修改父結點,用NULL作為孩子替換x *case2:如果x只有一個孩子:那麼用這個孩子來替換x *case3:如果x有兩個孩子,那麼x的後繼必然是右子樹中沒有左孩子的節點 *         case1‘:x的後繼有右孩子,此時轉到case2 *         case2’:x的後繼沒有右孩子,此時轉到case1 *這樣的話就調整以下順序,先處理case3,《演算法導論》樹中給出了更經典的方法,不過不是很直觀 */template<typename Key,typename Value>void bst_tree<Key,Value>::tree_delete(bst_node* x){bst_node* x_copy=x;//case3:if(x_copy->left_child!=NULL&&x_copy->right_child!=NULL){bst_node* y=tree_successor(x_copy);x_copy->key=y->key;x_copy->data=y->data;//有待改進x_copy=y;}if(x_copy->left_child==NULL && x_copy->right_child==NULL){//case1aux_transplant(x_copy,NULL);}else{//case2if(x_copy->left_child!=NULL){aux_transplant(x_copy,x_copy->left_child);}else{aux_transplant(x_copy,x_copy->right_child);}}}//----------------------------------------------------------------------------------

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.