日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构和算法分析学习笔记(三)--二叉查找树的懒惰删除(lazy deletion)

發(fā)布時間:2023/12/13 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构和算法分析学习笔记(三)--二叉查找树的懒惰删除(lazy deletion) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

??? 這次的問題來自《數(shù)據(jù)結(jié)構(gòu)與算法分析(C++描述)》的習(xí)題4.16,如下:

--------------------------

4.16? 重做二叉查找樹類以實現(xiàn)懶惰刪除.注意,這將影響所有的例程.特別具有挑戰(zhàn)性的是findMin和findMax,它們現(xiàn)在必須遞歸的完成.

--------------------------

??? 這題沒有參考答案,我也不敢保證自己寫的是對的,有不對的地方請指正,謝謝.先做一下說明,首先這只是一般的二叉查找樹,不是AVL樹.其次其中的printTree()函數(shù)只是將樹中的結(jié)點按升序打印出來,不是像樹的結(jié)構(gòu)那樣打印(可以參見這里的print()函數(shù)).最后,我定義的數(shù)據(jù)結(jié)構(gòu)是在有重復(fù)項的情況下使用的.也就是說,每一個結(jié)點有一個記錄數(shù)據(jù)出現(xiàn)次數(shù)的成員count(非負(fù)整數(shù)).當(dāng)?shù)谝淮尾迦肽骋粩?shù)據(jù)時,count為1,以后每插入一次這一數(shù)據(jù)則它的count加1.而當(dāng)某一數(shù)據(jù)沒有被實際刪除且它的count大于0時,對它的刪除操作就是將它的count減1.當(dāng)邏輯上被刪除的結(jié)點(count值為0的結(jié)點)的數(shù)目達(dá)到實際上存在的總結(jié)點數(shù)目的一半時,就對二叉查找樹進(jìn)行真正的刪除操作(delete).

??? 下面在課本中給出的一般二叉查找樹結(jié)構(gòu)(參見書中圖4-16至圖4-28)的基礎(chǔ)上進(jìn)行修改,得到我們所需要的結(jié)構(gòu).首先自然是結(jié)點的結(jié)構(gòu),如前所述,需要對結(jié)點BinaryNode類增加一個記錄數(shù)據(jù)出現(xiàn)次數(shù)的成員count.而在BSTree類中,我們需要兩個int型的私有成員分別統(tǒng)計樹的總結(jié)點數(shù)和其中在邏輯上已經(jīng)被刪除的結(jié)點數(shù).接下來是contains(),makeEmpty(),printTree()和insert(),這些都比較簡單.

? ? 我與課本上makeEmpty( BinaryNode * & t )(置空操作)的不同是,我沒有在最后將節(jié)點置為NULL,而是在調(diào)用這個函數(shù)之后將實參置為NULL,不知道這樣做會不會有什么錯誤.對于insert函數(shù),我們可以看到這種結(jié)構(gòu)的好處,對于那些僅在邏輯上被刪除的數(shù)據(jù),重新插入它只需要將count加1并且將delSize減1.

1 template <typename Object>
2 class BSTree
3 {
4 public:
5 BSTree( ){theSize=delSize=0;root=NULL;}
6 ~BSTree( )
7 {
8 makeEmpty(root);
9 theSize=delSize=0;
10 }
11
12 bool contains( const Object & x ) const//是否包含某值
13 {return contains(x,root);}
14 bool isEmpty( ) const//是否為空
15 {return theSize-delSize==0;}
16 void printTree( ) const//打印樹
17 {printTree(root);}
18
19 void makeEmpty( )//置空
20 {
21 makeEmpty(root);
22 theSize=delSize=0;root=NULL;
23 }
24 void insert( const Object & x )//插入值
25 {insert(x,root);}
26
27 private:
28 struct BinaryNode
29 {
30 Object element;//Object類型的值
31 BinaryNode *left;//左子樹
32 BinaryNode *right;//右子樹
33 int count; //計數(shù)
34
35 BinaryNode( const Object & theElement, BinaryNode *lt, BinaryNode *rt ,int c=1)//第一次插入值為1
36 : element( theElement ), left( lt ), right( rt ), count(c) { }
37 };
38
39 BinaryNode *root;//根結(jié)點
40 int theSize;
41 int delSize;
42
43 void insert( const Object & x, BinaryNode * & t ) ;
44
45 bool contains( const Object & x, BinaryNode *t ) const;
46 void makeEmpty( BinaryNode * & t );
47 void printTree( BinaryNode *t ) const
48 {
49 if(t)
50 {
51 printTree(t->left);
52 if(t->count>0)std::cout<<t->element<<" ";
53 printTree(t->right);
54 }
55 }
56 }; 1 template <typename Object>
2 bool BSTree<Object>::contains( const Object & x, BinaryNode *t ) const
3 {
4 if(!t)return false;
5 if(x<t->element)
6 return contains(x,t->left);
7 else if(x>t->element)
8 return contains(x,t->right);
9 else if(t->count>0)
10 return true;
11 else
12 return false;
13 }
14
15 template <typename Object>
16 void BSTree<Object>::makeEmpty( BinaryNode * & t )
17 {
18 if(t)
19 {
20 makeEmpty(t->left);
21 makeEmpty(t->right);
22 delete t;
23 }
24 }
25
26 template <typename Object>
27 void BSTree<Object>::insert( const Object & x, BinaryNode * & t )
28 {
29 if(t==NULL)
30 {
31 ++theSize;
32 t=new BinaryNode(x,NULL,NULL);//count默認(rèn)為1
33 }
34 else if(x<t->element)
35 insert(x,t->left);
36 else if(x>t->element)
37 insert(x,t->right);
38 else if(t->count++==0)
39 --delSize;//如果count的值原本為0,則將其加1的同時要將delSize減1.
40 }

? ? 接下來是remove操作,現(xiàn)在remove也顯得代價更小,當(dāng)刪除某項數(shù)據(jù)時,只需要將它的count減1而不需要從樹真正刪除它.而當(dāng)它的count為0時,則需要將delSize加1以表示又有一個結(jié)點在邏輯上已經(jīng)被刪除.最后再檢查delSize是否達(dá)到了theSize的一半.如果達(dá)到,則執(zhí)行真正的delete操作.

1 template <typename Object>
2 void BSTree<Object>::remove( const Object & x, BinaryNode * & t )
3 {
4 if(t==NULL)return;
5 if(x<t->element)
6 remove(x,t->left);
7 else if(x>t->element)
8 remove(x,t->right);
9 else if(t->count>0&&--(t->count)==0&&(++delSize>=theSize-delSize))
10 //若count大于0,則減1;若減1后為0,則delSize加1;
11 //若delSize達(dá)到theSize的一半,則執(zhí)行delete操作
12 {
13 delete_nodes(root);//真正的刪除操作
14 theSize-=delSize;//更新總結(jié)點數(shù)
15 delSize=0;//delSize歸零
16 }
17 }

? ? 現(xiàn)在的問題是delete_nodes( BinaryNode * & t )例程的實現(xiàn),我們要刪除樹中所有count為0的結(jié)點.我這里使用了遞歸的方法,如果某個結(jié)點不必刪除,那么就繼續(xù)對它的左子樹和右子樹執(zhí)行delete_nodes().回想一般二叉查找樹的刪除,對于葉子結(jié)點,直接刪除即可,這在delete_nodes()中也是一樣.而對于只有一個非空子樹的結(jié)點,直接刪除后將它的非空子樹"拼接"上即可,但這時需要對拼接上的子樹繼續(xù)執(zhí)行delete_nodes().

? ? 最后就是刪除那些兩個子樹都非空的結(jié)點,我們還是在它的右子樹上找到一個值最小的結(jié)點(注意:要在count大于0的結(jié)點中找),我們假設(shè)這個點為min.然后將t的值和count值都替換成min相應(yīng)的值,同時將min的count值修改為0以保證稍后刪除.最后,繼續(xù)對t的左子樹和右子樹執(zhí)行delete_nodes()操作.這里面一個可能存在的情況是t的右子樹中所有結(jié)點的count值都為0,那么我們可以將它的右子樹置空,這樣t就變成了一個只有一個非空子樹的結(jié)點.

? ? 在實際的編程中,我覺得比較費腦筋的就是findMin()findMax()例程.以findMin(BinaryNode *t)為例,首先要找到t中的最小值,然后再升序一步步往上尋找第一個count大于0的結(jié)點.我采用的遞歸的方法,這一例程返回bool值,false表示沒有找到最小值,也就意味著t為空或者t中所有結(jié)點的count均為0.而為了保存查找到的最小(最大)結(jié)點,我給BSTree類增加了兩個私有成員,兩個BinaryNode *類型的指針min和max.另外,我還提供了兩個公有的函數(shù),分別返回整顆樹的最小和最大值,但是這兩個函數(shù)需要在保證整顆樹非空的情況下使用.

1 private:
2 BinaryNode *min;
3 BinaryNode *max;
4
5 template <typename Object>
6 bool BSTree<Object>::findMin( BinaryNode *t )
7 {
8 if(t)
9 {
10 if(findMin(t->left))return true;//在t的左子樹中找到count大于0的點,查找結(jié)束.
11 if(t->count>0){min=t;return true;}//找到count大于0的點,查找結(jié)束.
12 return findMin(t->right);//否則繼續(xù)查找右子樹
13 }
14 return false;//空結(jié)點則返回false
15 }
16
17 template <typename Object>
18 bool BSTree<Object>::findMax( BinaryNode *t)
19 {
20 if(t)
21 {
22 if(findMax(t->right))return true;
23 if(t->count>0){max=t;return true;}
24 return findMax(t->left);
25 }
26 return false;
27 }
28
29 template <typename Object>
30 void BSTree<Object>::delete_nodes(BinaryNode * & t )
31 {
32 if(t==NULL)return;//空子樹,do nothing
33 if(t->count==0)//t需要被刪除
34 {
35 if((t->left!=NULL)&&(t->right!=NULL)&&findMin(t->right))
36 //t的兩個子樹均非空,且在它的右子樹中找到了可用的最小結(jié)點
37 {
38 t->element=min->element;
39 t->count=min->count;
40 min->count=0;//右子樹中的最小結(jié)點即將被刪除
41 delete_nodes(t->left);
42 delete_nodes(t->right);
43 }
44 else
45 {
46 if((t->left!=NULL)&&(t->right!=NULL))
47 //t的右子樹中的所有結(jié)點的count均為0,則將其置空.
48 {makeEmpty(t->right);t->right=NULL;}
49 BinaryNode *oldnode=t;
50 t=t->left?t->left:t->right;
51 delete oldnode;
52 if(t!=NULL)delete_nodes(t);//若新的t非空,繼續(xù)對它執(zhí)行刪除操作
53 }
54 }
55 else//t不需要被刪除,繼續(xù)在它的子樹中查找
56 {
57 delete_nodes(t->left);
58 delete_nodes(t->right);
59 }
60 }
61
62 public:
63 const Object & findMin( )//返回最小值
64 {
65 if(!findMin(root))
66 std::cerr<<"The tree is Empty!"<<std::endl;
67 return min->element;
68 }
69
70 const Object & findMax( )//返回最大值
71 {
72 if(!findMax(root))
73 std::cerr<<"The tree is Empty!"<<std::endl;
74 return max->element;
75 }

? ? 最后提供我的BSTree.h文件,有不對的地方請指正,謝謝.
? ??BSTree.h



轉(zhuǎn)載于:https://www.cnblogs.com/heqile/archive/2011/12/08/2280120.html

總結(jié)

以上是生活随笔為你收集整理的数据结构和算法分析学习笔记(三)--二叉查找树的懒惰删除(lazy deletion)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。