数据结构——二叉树操作

本次博客,我将记录数据结构中的二叉树操作及其代码

[1]定义

1.定义二叉树结点
struct BiNode{
	ElemType data;		//数据元素
	BiNode *lchild;		//指向左子树的指针
	BiNode *rchild;		//指向右子树的指针
	int pushNum=0;		//针对非递归后序遍历设置的标志位, 表示入栈的次数
};
2.定义二叉树
class BiTree{
	private:
		void createNode(BiNode *&t); 			//创建二叉树的递归函数
		void deleteNode(BiNode *t); 			//删除二叉树结点的递归函数
		int height(BiNode *t); 				//计算二叉树高度的递归函数
		int numOfLeaf(BiNode *t); 			//计算叶子结点数的递归函数
		int numOfNodes(BiNode *t); 			//计算结点数的递归函数
		BiNode* search(BiNode *t, ElemType e); 		//查找值为e的结点的递归函数
		void preOrder(BiNode *t); 			//先序遍历递归函数
		void inOrder(BiNode *t); 			//中序遍历递归函数
		void postOrder(BiNode *t); 			//后序遍历递归函数
	public:
		BiTree();	//构造函数
		~BiTree();	//析构函数
		BiNode* root;					//根结点
		void createBiTree(); 				//创建二叉树
		void deleteBiTree();				//删除二叉树
		int heightOfBiTree(); 				//计算二叉树的高度
		int numOfBTLeaf(); 				//计算二叉树的叶子结点数
		int numOfBTNodes(); 				//计算二叉树的结点数
		int numOfBTNodesDegree2(); 			//计算二叉树度为2的结点数
		BiNode* searchBTNode(ElemType e); 		//在二叉树中查找值为e的结点
		void preOrderBTTraverse(); 			//递归:先序遍历二叉树
		void inOrderBTTraverse(); 			//递归:中序遍历二叉树
		void postOrderBTTraverse(); 			//递归:后序遍历二叉树
		void preOrderBTTraverse_NonRec();		//非递归:先序遍历二叉树
		void inOrderBTTraverse_NonRec();		//非递归:中序遍历二叉树
		void postOrderBTTraverse_NonRec();		//非递归:后序遍历二叉树
		void levelOrderTraverse();			//非递归:层次遍历二叉树
		int numOfBTLeaf_NonRec();			//非递归:计算二叉树的叶子结点数
};
3.一些其他操作
class Solution{
	public:
		void exchangeSubTree(BiNode *&t);		//交换二叉树的左子树和右子树
		bool isSimilar(BiNode *a, BiNode *b); 		//判断两棵二叉树是否相似
		//二叉树的递归拷贝
		void copyBiNode(BiNode *t, BiNode *&p);
		void copyBiTree1(BiTree *t, BiTree *&p);
		//二叉树的非递归拷贝
		void copyBiTree2(BiTree *t, BiTree *&p);
};

[2]实现

1.二叉树的构造和析构函数
BiTree::BiTree(){
	root=nullptr;
}
BiTree::~BiTree(){
	if(root){
		deleteNode(root);
	}
}
2.递归创建二叉树
void BiTree::createNode(BiNode *&t){
	//输入该结点的数据,若为#,则该节点为空
	ElemType e;
	cin>>e;
	if(e=='#') t=nullptr;
	else{
		t=new BiNode;
		t->data=e;
		//分别创建左右子树
		createNode(t->lchild);
		createNode(t->rchild);
	}
}
void BiTree::createBiTree(){
	createNode(root);
}
3.删除二叉树
void BiTree::deleteNode(BiNode* t){
	if(t){
		deleteNode(t->lchild); //递归删除左子树
		deleteNode(t->rchild); //递归删除右子树
		delete t;		//删除根节点
	}
}
void BiTree::deleteBiTree(){
	if(root!=nullptr){
		deleteNode(root);
	}
}
4.计算二叉树的高度
int BiTree::height(BiNode* t){
	int lheight=0, rheight=0;
	if(t==nullptr) return 0;
	lheight=height(t->lchild);
	rheight=height(t->rchild);
	return lheight>=rheight?lheight+1:rheight+1;
}
int BiTree::heightOfBiTree(){
	return height(root);
}
5.计算二叉树的叶子结点数
1.递归
int BiTree::numOfLeaf(BiNode *t){
	int num_l_leaf, num_r_leaf;
	if(t==nullptr){
		return 0;
	}
	//分别计算左右子树的叶子结点数
	num_l_leaf=numOfLeaf(t->lchild);
	num_r_leaf=numOfLeaf(t->rchild);
	if(num_l_leaf+num_r_leaf==0){
		//若该结点是叶子结点,返回1
		return 1;
	}
	else{
		//若该结点不是叶子结点,则返回该结点的叶子结点数
		return num_l_leaf+num_r_leaf;
	}
}
int BiTree::numOfBTLeaf(){
	return numOfLeaf(root);
}
2.非递归
int BiTree::numOfBTLeaf_NonRec(){
	int num=0;
	BiNode *p=root;
	stack<BiNode*> ss;
	while(p||!ss.empty()){
		while(p){
			ss.push(p);
			p=p->lchild;
		}
		if(!ss.empty()){
			p=ss.top();
			ss.pop();
			if(p->lchild==nullptr&&p->rchild==nullptr) num++;
			p=p->rchild;
		}
	}
	return num;
}
6.计算二叉树结点数
int BiTree::numOfNodes(BiNode *t){
	if(t==nullptr) return 0;
	return numOfNodes(t->lchild)+numOfNodes(t->rchild)+1;
}
int BiTree::numOfBTNodes(){
	return numOfNodes(root);
}
7.搜索二叉树中数据为e的结点
BiNode* BiTree::search(BiNode *t, ElemType e){
	BiNode *temp=nullptr;
	if(t==nullptr) return nullptr;
	if(t->data==e) return t;
	temp=search(t->lchild,e);
	//如果temp不为null,说明在左子树中已经找到目标结点
	//于是只要返回temp即可
	//若没有在左子树中找到目标结点,则开始遍历右子树
	if(temp!=nullptr) return temp;
	else return search(t->rchild,e);
}
BiNode* BiTree::searchBTNode(ElemType e){
	return search(root, e);
}
8.计算二叉树中度为2的结点数
int BiTree::numOfBTNodesDegree2(){
	//计算二叉树度为2的结点数
	//我们利用公式n0=n2+1,因此只需要找到叶子结点数-1即可
	if(root==nullptr) return 0;
	return numOfBTLeaf()-1;
}
9.先序遍历二叉树
1.递归
void BiTree::preOrder(BiNode *t){
	//先序遍历二叉树
	if(t){
		cout<<t->data<<' ';
		preOrder(t->lchild);
		preOrder(t->rchild);
	}
}
void BiTree::preOrderBTTraverse(){
	//先序遍历二叉树
	preOrder(root);
	cout<<'\n';
}
2.非递归
void BiTree::preOrderBTTraverse_NonRec(){
	BiNode *p=root;
	stack<BiNode*> ss;
	//若p为空或栈为空,遍历结束
	//先序遍历顺序:根-左-右
	while(p||!ss.empty()){
		if(p){
			cout<<p->data<<' ';
			ss.push(p);
			p=p->lchild;
		}
		else{
			p=ss.top();
			ss.pop();
			p=p->rchild;
		}
	}
	cout<<'\n';
}
10.中序遍历二叉树
1.递归
void BiTree::inOrder(BiNode *t){
	if(t){
		inOrder(t->lchild);
		cout<<t->data<<' ';
		inOrder(t->rchild);
	}
}
void BiTree::inOrderBTTraverse(){
	//中序遍历二叉树
	inOrder(root);
	cout<<'\n';
}
2.非递归
void BiTree::inOrderBTTraverse_NonRec(){
	BiNode *p=root;
	stack<BiNode*> ss;
	//中序遍历顺序:左-根-右
	while(p||!ss.empty()){
		if(p){
			ss.push(p);
			p=p->lchild;
		}
		else{
			p=ss.top();
			ss.pop();
			cout<<p->data<<' ';
			p=p->rchild;
		}
	}
	cout<<'\n';
}
11.后序遍历二叉树
1.递归
void BiTree::postOrder(BiNode *t){
	if(t){
		postOrder(t->lchild);
		postOrder(t->rchild);
		cout<<t->data<<' ';
	}
} 
void BiTree::postOrderBTTraverse(){
	//后序遍历二叉树
	postOrder(root);
	cout<<'\n';
}
2.非递归
void BiTree::postOrderBTTraverse_NonRec(){
	BiNode *p=root;
	stack<BiNode*> ss;
	//后序遍历顺序:左-右-根
	while(p||!ss.empty()){
		if(p){
			p->pushNum++;
			ss.push(p);
			p=p->lchild;
		}
		else{
			p=ss.top();
			ss.pop();
			//如果p入过一次栈,那么将其二次入栈
			if(p->pushNum==1){
				p->pushNum++;
				ss.push(p);
				p=p->rchild;
			}
			else{
				//最后输出根结点的数据
				cout<<p->data<<' ';
				//注意,访问完该结点,由于要访问该结点双亲结点的右-根,故将其设为null
				p=nullptr;
			}
		}
	}
	cout<<'\n';
}
12.二叉树的层次遍历
void BiTree::levelOrderTraverse(){
	BiNode *p=root;
	queue<BiNode*>lq;
	if(p) lq.push(p);
	while(!lq.empty()){
		p=lq.front();
		lq.pop();
		cout<<p->data<<' ';
		if(p->lchild) lq.push(p->lchild);
		if(p->rchild) lq.push(p->rchild);
	}
	cout<<'\n';
}
13.交换二叉树的左右子树
void Solution::exchangeSubTree(BiNode *&t){
	//递归:交换二叉树的左右子树
	BiNode *temp;
	if(t){
		//交换t结点的左右结点
		temp=t->lchild;
		t->lchild=t->rchild;
		t->rchild=temp;
		//继续交换t结点左右子结点各自的左右结点
		exchangeSubTree(t->lchild);
		exchangeSubTree(t->rchild);
	}
}
14.判断两棵二叉树是否相似
bool Solution::isSimilar(BiNode *a, BiNode *b){
	if(a==nullptr&&b==nullptr) return true;
	if(a==nullptr||b==nullptr) return false;
	else return isSimilar(a->lchild, b->lchild) && isSimilar(a->rchild, b->rchild);
}
15.拷贝二叉树
1.递归
void Solution::copyBiNode(BiNode *t, BiNode *&p){
	if(t==nullptr){
		p=nullptr;
		return;
	}
	p=new BiNode;
	p->data=t->data;
	copyBiNode(t->lchild,p->lchild);
	copyBiNode(t->rchild,p->rchild);
}
void Solution::copyBiTree1(BiTree *t, BiTree *&p){
	//利用递归算法将二叉树t拷贝至p 
	if(t==nullptr) {
		return;
	}
	p=new BiTree();
	copyBiNode(t->root,p->root);
}
2.非递归
void Solution::copyBiTree2(BiTree *t, BiTree *&p){
	//通过遍历二叉树并将t拷贝至p
	p=new BiTree();
	BiNode *nt=t->root;
	BiNode *newp;
	if(!t||!t->root) return;
	stack<BiNode*> stack_t, stack_p;
	//若目标二叉树为空,则无需拷贝
	if(nt==nullptr) return;
	//新建头结点并初始化
	newp=new BiNode;
	newp->data=nt->data;
	newp->lchild=newp->rchild=nullptr;
	//将头结点入栈
	stack_t.push(nt);
	stack_p.push(newp);
	while(!stack_t.empty()){
		//取出头结点
		BiNode* nt=stack_t.top();
		BiNode* np=stack_p.top();
		stack_t.pop();
		stack_p.pop();
		//若该结点的右孩子不为空,则将右孩子入栈并将该结点拷贝
		if(nt->rchild!=nullptr){
			stack_t.push(nt->rchild);
			np->rchild=new BiNode;
			np->rchild->data=nt->rchild->data;
			np->rchild->lchild=np->rchild->rchild=nullptr;
			stack_p.push(np->rchild);
		}
		//若该结点的左孩子不为空,则将左孩子入栈并将该结点拷贝
		if(nt->lchild!=nullptr){
			stack_t.push(nt->lchild);
			np->lchild=new BiNode;
			np->lchild->data=nt->lchild->data;
			np->lchild->lchild=np->lchild->rchild=nullptr;
			stack_p.push(np->lchild);
		}
	}
	p->root=newp;
}
main函数
int main()
{
	BiTree* b=new BiTree();
	b->createBiTree();
	cout<<"对二叉树b先序、中序、后序递归遍历"<<'\n';
	b->preOrderBTTraverse();
	b->inOrderBTTraverse();
	b->postOrderBTTraverse();
	cout<<'\n';
	cout<<"对二叉树b先序、中序、后序非递归遍历"<<'\n';
	b->preOrderBTTraverse_NonRec();
	b->inOrderBTTraverse_NonRec();
	b->postOrderBTTraverse_NonRec();
	cout<<'\n';
	cout<<"对二叉树b层次遍历"<<'\n';
	b->levelOrderTraverse();
	return 0;
}
一些测试用例
测试用例1
A
B
E
#
#
C
D
#
#
#
F
#
G
H
#
I
#
#
J
#
#
测试用例2
A
B
D
H
#
#
I
#
#
E
#
#
C
F
#
#
G
#
#
运行结果:
测试用例1
对二叉树b先序、中序、后序递归遍历
A B E C D F G H I J
E B D C A F H I G J
E D C B I H J G F A

对二叉树b先序、中序、后序非递归遍历
A B E C D F G H I J
E B D C A F H I G J
E D C B I H J G F A

对二叉树b层次遍历
A B F E C G D H J I
测试用例2
对二叉树b先序、中序、后序递归遍历
A B D H I E C F G
H D I B E A F C G
H I D E B F G C A

对二叉树b先序、中序、后序非递归遍历
A B D H I E C F G
H D I B E A F C G
H I D E B F G C A

对二叉树b层次遍历
A B C D E F G H I

本文完

posted @ 2023-03-28 08:42  Sky6634  阅读(60)  评论(1)    收藏  举报