【二叉树】二叉树的创建、遍历、销毁、求树的最大深度

建立二叉树的链式存储结构,并对二叉树前序遍历、中序遍历、后序遍历以及层序遍历,求二叉树的深度,销毁二叉树。

(1)二叉树的建立

前序建立,即先建立根节点,再建立左子树,最后建立右子树,结点值的输入需要按照先序遍历的方式输入,以-1表示结点为空,例如一个深度为3的二叉树每层分别为1 ,2 3, 4 5 6 7,则应输入1 2 4 -1 -1 5 -1 -1 3 6 -1 -1 7 -1 -1。

BiTreeNode *CreateBiTree()//建立树,输入结点值,输入-1表示结点为空,输入非数字结束
{
	int n;
	BiTreeNode *T;
	if(!(cin>>n))//如果输入非法,则返回NULL
		return NULL;
	else if(n==-1)//输入-1,表示该结点为空
		T=NULL;
	else
	{
		T=new BiTreeNode;//分配内存
		T->value=n;
		T->lchild=CreateBiTree();
		T->rchild=CreateBiTree();
	}
	return T;
}

(2)二叉树的遍历
基于二叉树的递归定义,可以得到二叉树的递归遍历算法

前序遍历:二叉树为空,空操作。先访问根结点,前序遍历左子树,前序遍历右子树

递归算法

void PreOrderTraverse(BiTreeNode *T)//先序遍历
{
	if(T)
	{
		cout<<T->value<<" ";//
		PreOrderTraverse(T->lchild);//
		PreOrderTraverse(T->rchild);
	}
}

非递归算法

思路:先将根节点入栈,将其左结点依次入栈,一直到左结点为空,然后一层层退栈处理其右子树,对每一次退栈的元素的右结点执行与根节点相同的操作,在每个元素入栈之前输出,即可实现先头结点,再左子树,再右子树的先序遍历

void NPreOrderTraverse(BiTreeNode *T)//非递归先序遍历
{
	BiTreeNode *p=T;
	stack<BiTreeNode*> nodes;
	while(p!=NULL || !nodes.empty())
	{
		while(p!=NULL)
		{
			cout<<p->value<<" ";
			nodes.push(p);
			p=p->lchild;
		}
		if(!nodes.empty())
		{
			p=nodes.top();
			nodes.pop();
			p=p->rchild;
		}
	}
}

中序遍历:二叉树为空,空操作。中序遍历左子树,访问根结点,中序遍历右子树

void InOrderTraverse(BiTreeNode *T)//中序遍历
{
	if(T)
	{
		InOrderTraverse(T->lchild);//
		cout<<T->value<<" ";//
		InOrderTraverse(T->rchild);//
	}
}

非递归算法:思路与前序遍历相同,但输出是在元素退栈之后,这样才能保证左结点先输出

void NInOrderTraverse(BiTreeNode *T)//非递归中序遍历
{
	BiTreeNode *p=T;
	stack<BiTreeNode*> nodes;
	while(p!=NULL || !nodes.empty())
	{
		while(p!=NULL)
		{
			nodes.push(p);
			p=p->lchild;
		}
		if(!nodes.empty())
		{
			p=nodes.top();
			cout<<p->value<<" ";
			nodes.pop();
			p=p->rchild;
		}
	}
}

后序遍历:二叉树为空,空操作。后序遍历左子树,后序遍历右子树,访问根结点

void PostOrderTraverse(BiTreeNode *T)//后序遍历
{
	if(T)
	{
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		cout<<T->value<<" ";	
	}
}

非递归算法:根节点需要在最后遍历,因此按照之前前序非递归的思路不能实现后序遍历

思路:对于任一结点,先将其入栈。如果不存在子结点,则可以直接输出,如果存在左孩子或者右孩子,且左孩子和右孩子都已入过栈,也可以直接输出,如果存在左右孩子且没有被访问,则将右孩子和左孩子依次入栈(这个顺序很重要,保证了左孩子比右孩子先出栈,先被处理和访问)

void NPostOrderTraverse(BiTreeNode *T)//非递归后序遍历
{
	BiTreeNode *p=T;
	BiTreeNode *cur,*pre=NULL;
	stack<BiTreeNode*> s;
	if(T!=NULL)
		s.push(T);
	while(!s.empty())
	{
		cur=s.top();
		if((cur->lchild==NULL&&cur->rchild==NULL)||(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
		{
			cout<<cur->value<<" ";
			s.pop();
			pre=cur;
		}
		else
		{
			if(cur->rchild!=NULL)
				s.push(cur->rchild);
			if(cur->lchild!=NULL)
				s.push(cur->lchild);
		}
	}
}

层序遍历:二叉树为空,空操作。从根结点开始,按层遍历二叉树

思路;从根结点开始,对每层元素,都依次将其左右结点压入序列,记录序列每层结点开始与结束的位置,即可按层遍历。

void LevelOrderTraverse(BiTreeNode *T)//层序遍历
{//若要输出单层结点,只需在第一个while循环中加入变量depth记录层数,只在指定层输出即可
	if(T)
	{
		vector<BiTreeNode*> vec;//存放结点
		int cur=0,last=1;
		vec.push_back(T);//把第一层压入vec
		while(cur<vec.size())//cur进行当前层的遍历
		{
			last=vec.size();//到当前层为止的所有结点数
			while(cur<last)
			{//此处的while循环结束后,cur已经遍历完当前层,vec已把当前层结点的左右孩子都压入。
				cout<<vec[cur]->value<<" ";
				if(vec[cur]->lchild!=NULL)	
					vec.push_back(vec[cur]->lchild);
				if(vec[cur]->rchild!=NULL)
					vec.push_back(vec[cur]->rchild);
				cur++;
			}
		}
	}
}

(3)求二叉树的深度
若根结点为空,则返回深度为0,否则按照递归的方法,依次求左子树和右子树的深度,返回较大的深度值,加1(因为还要加上该结点的这一层)后返回。递归完毕即可求得深度值。

int TreeDepth(BiTreeNode *root) //求树的最大深度
{
        if (root == NULL)
            return 0;
        int left = TreeDepth(root->lchild);
        int right = TreeDepth(root->rchild);
        if (left > right)
            return left + 1;
        else
            return right + 1;
}

(4)销毁二叉树
同样按照递归的方式销毁二叉树,释放内存

void DestroyBiTree(BiTreeNode *&T)//销毁一棵树
{
	if(T!=NULL)
	{
		DestroyBiTree(T->lchild);
		DestroyBiTree(T->rchild);
		delete T;
	}
}

完整代码:

#include<iostream>
#include<vector>
#include<stack>
using namespace std;
struct BiTreeNode//树的结构
{
	int value;
	BiTreeNode *lchild;
	BiTreeNode *rchild;
};
struct FlagNode
{
	int isfirst;
	BiTreeNode *node;
};
BiTreeNode *CreateBiTree()//建立树,输入结点值,输入-1表示结点为空,输入非数字结束
{
	int n;
	BiTreeNode *T;
	if(!(cin>>n))//如果输入非法,则返回NULL
		return NULL;
	else if(n==-1)//输入-1,表示该结点为空
		T=NULL;
	else
	{
		T=new BiTreeNode;//分配内存
		T->value=n;
		T->lchild=CreateBiTree();
		T->rchild=CreateBiTree();
	}
	return T;
}
void PreOrderTraverse(BiTreeNode *T)//先序遍历
{
	if(T)
	{
		cout<<T->value<<" ";//
		PreOrderTraverse(T->lchild);//
		PreOrderTraverse(T->rchild);
	}
}
void InOrderTraverse(BiTreeNode *T)//中序遍历
{
	if(T)
	{
		InOrderTraverse(T->lchild);//
		cout<<T->value<<" ";//
		InOrderTraverse(T->rchild);//
	}
}
void PostOrderTraverse(BiTreeNode *T)//后序遍历
{
	if(T)
	{
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		cout<<T->value<<" ";	
	}
}
void NPreOrderTraverse(BiTreeNode *T)//非递归先序遍历
{
	BiTreeNode *p=T;
	stack<BiTreeNode*> nodes;
	while(p!=NULL || !nodes.empty())
	{
		while(p!=NULL)
		{
			cout<<p->value<<" ";
			nodes.push(p);
			p=p->lchild;
		}
		if(!nodes.empty())
		{
			p=nodes.top();
			nodes.pop();
			p=p->rchild;
		}
	}
}
void NInOrderTraverse(BiTreeNode *T)//非递归中序遍历
{
	BiTreeNode *p=T;
	stack<BiTreeNode*> nodes;
	while(p!=NULL || !nodes.empty())
	{
		while(p!=NULL)
		{
			nodes.push(p);
			p=p->lchild;
		}
		if(!nodes.empty())
		{
			p=nodes.top();
			cout<<p->value<<" ";
			nodes.pop();
			p=p->rchild;
		}
	}
}
void NPostOrderTraverse(BiTreeNode *T)//非递归后序遍历
{
	BiTreeNode *p=T;
	BiTreeNode *cur,*pre=NULL;
	stack<BiTreeNode*> s;
	if(T!=NULL)
		s.push(T);
	while(!s.empty())
	{
		cur=s.top();
		if((cur->lchild==NULL&&cur->rchild==NULL)||(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
		{
			cout<<cur->value<<" ";
			s.pop();
			pre=cur;
		}
		else
		{
			if(cur->rchild!=NULL)
				s.push(cur->rchild);
			if(cur->lchild!=NULL)
				s.push(cur->lchild);
		}
	}
}
void LevelOrderTraverse(BiTreeNode *T)//层序遍历
{//若要输出单层结点,只需在第一个while循环中加入变量depth记录层数,只在指定层输出即可
	if(T)
	{
		vector<BiTreeNode*> vec;//存放结点
		int cur=0,last=1;
		vec.push_back(T);//把第一层压入vec
		while(cur<vec.size())//cur进行当前层的遍历
		{
			last=vec.size();//到当前层为止的所有结点数
			while(cur<last)
			{//此处的while循环结束后,cur已经遍历完当前层,vec已把当前层结点的左右孩子都压入。
				cout<<vec[cur]->value<<" ";
				if(vec[cur]->lchild!=NULL)	
					vec.push_back(vec[cur]->lchild);
				if(vec[cur]->rchild!=NULL)
					vec.push_back(vec[cur]->rchild);
				cur++;
			}
		}
	}
}
int TreeDepth(BiTreeNode *root) //求树的最大深度
{
        if (root == NULL)
            return 0;
        int left = TreeDepth(root->lchild);
        int right = TreeDepth(root->rchild);
        if (left > right)
            return left + 1;
        else
            return right + 1;
}
void DestroyBiTree(BiTreeNode *&T)//销毁一棵树
{
	if(T!=NULL)
	{
		DestroyBiTree(T->lchild);
		DestroyBiTree(T->rchild);
		delete T;
	}
}

int main()
{
	BiTreeNode *pTree;
	cout<<"二叉树的前序建立,输入二叉树:"<<endl;
	pTree=CreateBiTree();
	cout<<"先序遍历"<<endl;
	PreOrderTraverse(pTree);
	cout<<endl;
	cout<<"非递归先序遍历"<<endl;
	NPreOrderTraverse(pTree);
	cout<<endl;

	cout<<"中序遍历"<<endl;
	InOrderTraverse(pTree);
	cout<<endl;
	cout<<"非递归中序遍历"<<endl;
	NInOrderTraverse(pTree);
	cout<<endl;

	cout<<"后序遍历"<<endl;
	PostOrderTraverse(pTree);
	cout<<endl;
	cout<<"非递归后序遍历"<<endl;
	NPostOrderTraverse(pTree);
	cout<<endl;

	cout<<"层序遍历"<<endl;
	LevelOrderTraverse(pTree);
	cout<<endl;

	cout<<"树的深度为"<<endl;
	cout<<TreeDepth(pTree)<<endl;
	cout<<endl;
	DestroyBiTree(pTree);
	return 0;
}

    原文作者:HiPricilla
    原文地址: https://blog.csdn.net/yebanxin/article/details/52139030
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞