国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

夕拾算法進階篇:24)二叉樹排序樹

2019-11-08 02:57:56
字體:
來源:轉載
供稿:網友

二叉排序樹的定義

二叉排序樹又稱為排序二叉樹、二叉搜索樹,它的遞歸定義如下:

(1)要么二叉排序樹是一棵空樹。

(2)要么二叉排序樹由根節點、左子樹、右子樹組成,其中左右子樹都是二叉排序樹,且左子樹上所有節點的數據域均小于或等于根節點,右子樹的所有節點的數據域均大于根節點。

二叉排序樹的基本操作

二叉排序樹建立

對一棵二叉排序樹來說,插入的過程就是查找的過程,當查找失敗即root==NULL的時候就是插入的地方。

樹結構的定義:

//樹結構定義 struct Node{	int data;	Node *lchild,*rchild; 	 }; //簡單封裝下新建節點的操作 Node* newNode(int x){	Node* n=new Node();	n->data=x;	n->lchild=n->rchild=NULL; }二叉樹排序的插入操作:

//在二叉排序樹中插入數據域為x的新節點(注意root必須要添加&引用) void insert(Node* &root,int x){	if(root==NULL){ //空樹查找失敗,即插入的位置 		root=newNode(x); 	}else if(root->data>=x){//x節點比根節點小,說明x需要插在左子樹 		insert(root->lchild,x);//往左子樹搜索x 	}else {//x節點比根節點大,說明x需要插在右子樹 		insert(root->rchild,x);//往右子樹搜索x 	}}二叉排序樹的建立過程就是不斷插入的過程:

int a[6]={1,3,5,4,6,2};Node *root=NULL; //root初始為空 for(int i=0;i<6;i++){	insert(root,a[i]);}

二叉排序樹的刪除

如下圖所示要刪除根節點5,那應該怎么做呢?為了保證刪除之后仍然是一棵二叉排序樹,一種辦法是以樹種比5小的最大節點(也就是4節點,稱為5節點的前驅節點)覆蓋節點5,然后在刪除節點4;另一種方法就是把樹種比5大的最小節點(也就是節點6,稱為5節點的后繼節點)覆蓋節點5,然后刪除節點6。 (很明顯,這又是一個遞歸的操作)首先實現找到root的節點的前驅或者后繼節點,很明顯root節點的前驅節點就是其左子樹最靠右的節點,而后繼節點就是右子樹最靠左的節點。假設已經找到了待刪除的節點x,則有以下幾種情況:(1)如果當前的節點x不存在左右孩子,說明是葉子節點,直接刪除(2)如果當前的節點x存在左孩子,那么在x的左子樹中找到x的前驅節點PRe,然后讓節點pre覆蓋x節點的值,接著再刪除pre節點(3)如果當前的節點x存在右孩子,那么在x的右子樹中找到x的后繼節點next,然后讓節點next覆蓋x節點的值,接著再刪除next節點
//查找root節點的最小權值結點 Node* findMin(Node *root){	while(root->lchild){		root=root->lchild;	}	return root;} //查找root節點的最大權值結點 Node* findMax(Node *root){	while(root->rchild){		root=root->rchild;	}	return root;} //刪除以root為根節點的樹種權值為x的結點 Node* deleteNode(Node* &root,int x){ 	if(root){//樹不為空		if(root->data==x){//找到了待刪除結點 			if(root->lchild==NULL&&root->rchild==NULL){				root=NULL;			}else if(root->lchild){ //左孩子存在 				Node* pre=findMax(root->lchild);//獲得當前結點的前驅  				root->data=pre->data; //覆蓋當前root節點的值 				deleteNode(root->lchild,pre->data); //遞歸刪除pre節點 			}else{//右孩子存在 				Node* next=findMin(root->rchild); //獲得當前結點的后繼 				root->data=next->data;//覆蓋當前root節點的值				deleteNode(root->rchild,next->data); //遞歸刪除next節點 			} 		}else if(root->data>x){//節點x在當前節點的左子樹上 			deleteNode(root->lchild,x);		}else{//節點x在當前節點的右子樹上 				deleteNode(root->rchild,x);		} 	}}這里注意一個問題:在遞歸刪除當前root結點的前驅時deleteNode(root->lchild,pre->data),第一個參數如果直接使用pre,是沒有效果的。因為C++的引用類似于變量的別名,若使用pre在deleteNode中操作root實際上是操作的是pre,而不是root->lchild!上面的代碼遞歸刪除前驅和后繼的代碼還可以優化,比如上圖如用節點6來取代root結點,此時結點6已然無左子樹,而讓結點6的右子樹(若存在,為空亦可)取代結點6即可,因此在findMin中需要記錄前驅結點的父節點以便進行刪除操作。但注意這種情況,如果刪除的是結點3,而使用結點2進行取代,但結點3的左子樹只有一個結點(沒有進入findMax的while循環),因此只需root->lchild=NULL即可。
//查找root節點的最小權值結點 Node* findMin(Node *root,Node* &father){	while(root->lchild){		father=root;//記錄父節點		root=root->lchild;	}	return root;} //查找root節點的最大權值結點 Node* findMax(Node *root,Node* &father){	while(root->rchild){		father=root;		root=root->rchild;	}	return root;} //刪除以root為根節點的樹種權值為x的結點 Node* deleteNode(Node* &root,int x){ 	if(root){//樹不為空		if(root->data==x){//找到了待刪除結點 			if(root->lchild==NULL&&root->rchild==NULL){				root=NULL;			}else if(root->lchild){ //左孩子存在 				Node* f=root;//記錄前驅節點的父節點 				Node* pre=findMax(root->lchild,f);//獲得當前結點的前驅  				root->data=pre->data; //覆蓋當前root節點的值 				if(f==root){//說明root的左子樹只有一個結點 					f->lchild=NULL; //直接刪掉該結點 				}else{ //讓前驅節點(f->rchild)的左子樹取代前驅結點 					f->rchild=f->rchild->lchild;					}			}else{//右孩子存在 				Node* f=root;//記錄前驅節點的父節點 				Node* next=findMin(root->rchild,f); //獲得當前結點的后繼 				root->data=next->data;//覆蓋當前root節點的值				if(f==root){//說明root的右子樹只有一個結點					f->rchild=NULL; //直接刪掉該結點				}else{//讓后繼節點(f->lchild)的右子樹取代后繼節點 					f->lchild=f->lchild->rchild;					}			} 		}else if(root->data>x){//節點x在當前節點的左子樹上 			deleteNode(root->lchild,x);		}else{//節點x在當前節點的右子樹上 				deleteNode(root->rchild,x);		} 	}}


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宁阳县| 农安县| 永寿县| 沐川县| 遵化市| 玉门市| 卢龙县| 衡南县| 吉水县| 汕头市| 如皋市| 汨罗市| 鲁山县| 桐乡市| 嘉定区| 南投市| 陵川县| 张家界市| 图们市| 屏山县| 襄城县| 大化| 荔波县| 横峰县| 湘阴县| 恩施市| 砚山县| 虎林市| 长泰县| 九龙县| 小金县| 黄冈市| 元谋县| 张家界市| 普定县| 民权县| 荔浦县| 通州区| 铅山县| 金坛市| 讷河市|