二叉排序樹的創建,刪除結點;樹的前序,中序,後序非遞歸遍;二叉樹的線索化

#include<iostream>
#include<stack>
using namespace std;
typedef int ELEMENT_TYPE;
//定義樹的結點
typedef struct Node{
	ELEMENT_TYPE data;
	struct Node *lchild,*rchild; 
	int ltag,rtag;// 如果ltag=0,有左子樹lchild指向左子樹的根節點;如果ltag=1,lchild指向前驅
}BNode;

//定義樹的根節點,(全局變量)默認NULL
BNode* root;

// 向樹中插入結點,構造二叉排序樹
void InsertNodeToCreateTree(ELEMENT_TYPE element){
	//構造根節點
	if(root==NULL){
		root=new BNode();
		root->data=element;
		root->rchild=NULL;
		root->lchild=NULL;
	}
	else{
		BNode* parentNode=root;               //當前結點的父結點
		BNode* currentNode=root;              //當前結點
		//構造新的結點
		BNode* newNode=new BNode();
		newNode->data=element;
		newNode->lchild=NULL;
		newNode->rchild=NULL;
		while(currentNode!=NULL){
			parentNode=currentNode;
			if(currentNode->data>element){
				currentNode=currentNode->lchild;
			}
			else
				currentNode=currentNode->rchild;
		}
		if(parentNode->data>element)
			parentNode->lchild=newNode;
		else
			parentNode->rchild=newNode;
	}
}

//先序遞歸遍歷二叉樹
void PreOrder(BNode* p){
	if(p!=NULL){
		cout<<p->data<<" ";
		PreOrder(p->lchild);
		PreOrder(p->rchild);
	}
}

//先序非遞歸遍歷二叉樹
void PreOrderF(){
	BNode* p=root;
	stack<BNode*> stack;  //定義存放結點的棧
	while(!(p==NULL && stack.empty())){
		if(p!=NULL){
			cout<<p->data<<" ";
			if(p->rchild!=NULL)  //如果右子樹不爲空則進棧
				stack.push(p);
			p=p->lchild;
		}
		else{
			p=stack.top()->rchild;
			stack.pop();
		}
	}
	cout<<endl;
}
//中序遞歸遍歷二叉樹
void MiddleOrder(BNode* p){
	if(p!=NULL){
		MiddleOrder(p->lchild);
		cout<<p->data<<"  ";
		MiddleOrder(p->rchild);
	}
}
//中序非遞歸遍歷二叉樹
void MiddleOrderF(){
	BNode* p=root;
	stack<BNode*> stack;
	while(!(p==NULL && stack.empty())){
		//當前結點不爲空則進棧
		if(p!=NULL){
			stack.push(p);
			p=p->lchild;
		}
		else{
			p=stack.top();
			stack.pop();
			cout<<p->data<<"  ";
			p=p->rchild;
		}
	}
	cout<<endl;
}
//後序遞歸遍歷二叉樹
void PostOrder(BNode* p){
	if(p!=NULL){
		PostOrder(p->lchild);
		PostOrder(p->rchild);
		cout<<p->data<<"  ";
	}
}
//後序非遞歸遍歷二叉樹
void PostOrderF(){
	BNode* p=root;
	BNode* pre=NULL;  //指向當前訪問節點的前驅結點
	stack<BNode*> stack;
	while(!(p==NULL && stack.empty())){
		
		if(p!=NULL){
			stack.push(p);
			pre=p;
			p=p->lchild;
		}
		else{
			p=stack.top();  //取得棧頂元素
			//如果p的右子樹不爲空並且沒有訪問過,則訪問右子樹
			if(p->rchild!=NULL && p->rchild!=pre){
				pre=p;
				p=p->rchild;
			}
			//如果右子樹爲空或者已經訪問過,則訪問當前結點
			else{
				cout<<p->data<<"  ";
				stack.pop();  //右子樹爲空,或則已經訪問過,則訪問了當前結點後直接出棧
				pre=p;
				p=NULL; //爲下一輪遍歷準備
			}
		}
	}
}
// 二叉排序樹上刪除元素
void DeleteNode(ELEMENT_TYPE element){
	int flag=0;  //0表示當前結點在其父結點的左子樹上,1表示在其父結點的右子樹上   
	if(root==NULL){
		cout<<"錯誤,二叉樹爲空"<<endl;
	}
	else{
		BNode* currentNode=root;
		BNode* parentNode=NULL;
		while(currentNode->data!=element){
			parentNode=currentNode;
			if(currentNode->data>element)
			{
				flag=0;
				currentNode=currentNode->lchild;
			}
			else
			{
				flag=1;
				currentNode=currentNode->rchild;
			}
		}
		// 如果找到了指定元素的結點
		if(currentNode->data==element){
			if(flag==0)  //當前結點在其父節點的左子樹上
			{
				//判斷當前結點的子樹的情況:

				//當前結點爲葉子結點
				if(currentNode->lchild==NULL && currentNode->rchild==NULL){
					parentNode->lchild=NULL;
				}
				// 當前結點只有左子樹
				if(currentNode->lchild!=NULL && currentNode->rchild==NULL){
					parentNode->lchild=currentNode->lchild;
				}
				// 當前結點只有右子樹
				if(currentNode->lchild==NULL && currentNode->rchild!=NULL){
					parentNode->lchild=currentNode->rchild;
				}
				// 當前結點有左,右子樹
				if(currentNode->lchild!=NULL && currentNode->rchild!=NULL){
					parentNode->lchild=currentNode->rchild;
					BNode* rnode=currentNode->rchild;
					BNode* lnode=currentNode->lchild;
					//查找右子樹的最左結點
					while(rnode->lchild!=NULL)
						rnode=rnode->lchild;
					rnode->lchild=lnode;
				}
			}
			if(flag==1)  //當前結點在其父節點的右子樹上
			{
				//判斷當前結點的子樹的情況:

				//當前結點爲葉子結點
				if(currentNode->lchild==NULL && currentNode->rchild==NULL){
					parentNode->rchild=NULL;
				}
				// 當前結點只有左子樹
				if(currentNode->lchild!=NULL && currentNode->rchild==NULL){
					parentNode->rchild=currentNode->lchild;
				}
				// 當前結點只有右子樹
				if(currentNode->lchild==NULL && currentNode->rchild!=NULL){
					parentNode->rchild=currentNode->rchild;
				}
				// 當前結點有左,右子樹
				if(currentNode->lchild!=NULL && currentNode->rchild!=NULL){
					parentNode->rchild=currentNode->rchild;
					BNode* rnode=currentNode->rchild;
					BNode* lnode=currentNode->lchild;
					//查找右子樹的最左結點
					while(rnode->lchild!=NULL)
						rnode=rnode->lchild;
					rnode->lchild=lnode;
				}
			}
			delete currentNode;
		}
		// 如果沒有找到指定元素的結點
		else{
			cout<<"指定元素的結點不存在"<<endl;
		}
	}
}

// 中序遞歸線索二叉樹,注意第一個結點後最後一個結點(第一個沒有前驅,最後一個沒有後繼)   這兩個特殊情況
/*
* pre 表示中序遍歷事當前結點的前驅結點
*
*/
BNode* order_pre=NULL;
void InorderLining(BNode* p){
	if(p!=NULL){
		InorderLining(p->lchild);
		if(p->lchild==NULL){
			p->ltag=1;
			p->lchild=order_pre;//左節點指向根節點
		}
		if(order_pre!=NULL && order_pre->rchild==NULL)
		{
			order_pre->rtag=1;
			order_pre->rchild=p;
		}
		order_pre=p;
		InorderLining(p->rchild);
	}
}
// 根據中序線索化之後查找某個元素值結點的前驅和後繼
//需要注意的是,當對二叉樹進行線索化之後,結點的指針域發生了變化,原來有效的指針的條件都是tag==0
void FindPreAndPost(ELEMENT_TYPE element){
	if(root==NULL){
		cout<<"錯誤,二叉樹爲空"<<endl;
	}
	else{
		BNode* currentNode=root;
		while(currentNode!=NULL &¤tNode->data!=element){
			if(currentNode->ltag==1 && currentNode->rtag==1)  //實際上是原先的葉子結點
				break;
			if(currentNode->data>element && currentNode->ltag==0)
				currentNode=currentNode->lchild;
			if(currentNode->data<element && currentNode->rtag==0)
				currentNode=currentNode->rchild;
		}
		// 如果找到了指定元素的結點
		if(currentNode!=NULL &¤tNode->data==element){
			cout<<"當前結點的值:"<<element<<"   ";
			if(currentNode->ltag==1)
			{
				if(currentNode->lchild!=NULL)
					cout<<"前驅是:"<<currentNode->lchild->data<<"   ";
				else
					cout<<"前驅爲空"<<"   ";
			}
			//如果左子樹不爲空的話,則當前結點的前驅爲其左子樹的“最右下方”結點
			else{
				BNode* lnode=currentNode->lchild;
				while(lnode->rchild!=NULL && lnode->ltag==0)
					lnode=lnode->rchild;
				cout<<"前驅是:"<<lnode->data<<"   ";
			}
			if(currentNode->rtag==1)
			{
				if(currentNode->rchild!=NULL)
					cout<<"後繼是:"<<currentNode->rchild->data<<"   ";
				
			}
			//如果右子樹不爲空的話,則當前結點的後繼爲其右子樹樹的“最左下方”結點
			else{
				if(currentNode->rchild==NULL)  //如果是中序遍歷,線索化之後的最後一個結點沒有後繼
					cout<<"後繼爲空";
				else
				{
					BNode* rnode=currentNode->rchild;
					while(rnode->lchild!=NULL && rnode->ltag==0)
						rnode=rnode->lchild;
					cout<<"後繼是:"<<rnode->data<<"   ";
				}
			}
		}
		else
			cout<<"該節點不存在"<<endl;
	}
	cout<<endl;
}

//注意,對於程序中對二叉樹的遍歷的時候並沒有考慮線索化,所以針對排序二叉樹的建立,結點刪除,以及各種
//遍歷可以單獨測試

void test01(){
	//插入結點創建排序二叉樹
	InsertNodeToCreateTree(36);
	InsertNodeToCreateTree(57);
	InsertNodeToCreateTree(25);
	InsertNodeToCreateTree(18);
	InsertNodeToCreateTree(30);
	InsertNodeToCreateTree(68);
	InsertNodeToCreateTree(60);
	InsertNodeToCreateTree(59);
	InsertNodeToCreateTree(58);
	InsertNodeToCreateTree(65);
	InsertNodeToCreateTree(63);
	InsertNodeToCreateTree(67);
	InsertNodeToCreateTree(62);
	InsertNodeToCreateTree(64);

	//先序遍歷樹
	PreOrder(root);
	cout<<endl;
	PreOrderF();

	//中序遍歷樹
	MiddleOrder(root);
	cout<<endl;
	MiddleOrderF();

	//後序遍歷樹
	PostOrder(root);
	cout<<endl;
	PostOrderF();
	cout<<endl;
	//刪除結點
	DeleteNode(62);

	//遍歷樹
	PreOrder(root);
	cout<<endl;
	PreOrderF();

	MiddleOrder(root);
	cout<<endl;
	MiddleOrderF();

	//後序遍歷樹
	PostOrder(root);
	cout<<endl;
	PostOrderF();
	cout<<endl;
}

void test02(){
	//插入結點創建排序二叉樹
	InsertNodeToCreateTree(36);
	InsertNodeToCreateTree(57);
	InsertNodeToCreateTree(25);
	InsertNodeToCreateTree(18);
	InsertNodeToCreateTree(30);
	InsertNodeToCreateTree(68);
	InsertNodeToCreateTree(60);
	InsertNodeToCreateTree(59);
	InsertNodeToCreateTree(58);
	InsertNodeToCreateTree(65);
	InsertNodeToCreateTree(63);
	InsertNodeToCreateTree(67);
	InsertNodeToCreateTree(62);
	InsertNodeToCreateTree(64);

	//先序遍歷樹
	PreOrder(root);
	cout<<endl;
	PreOrderF();

	//中序遍歷樹
	MiddleOrder(root);
	cout<<endl;
	MiddleOrderF();

	//線索化二叉樹
	InorderLining(root);

	//找前驅後繼結點:
	FindPreAndPost(18);
	FindPreAndPost(30);
	FindPreAndPost(68);
	FindPreAndPost(65);
	FindPreAndPost(67);
	FindPreAndPost(62);
	FindPreAndPost(64);
	FindPreAndPost(55);
}
int main(){  
	test01();
	
	//test02();
	system("pause");
	return 0;
}

發佈了47 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章