二叉树的创建与各种遍历详解


二叉树大部分高级数据结构的基础,对这种基础的数据结构要达到非常熟练顺手拈来的程度才能对问题有更深一步的理解,今天为了巩固树这一部分,把二叉树的基本操作,建树,各种递归、非递归遍历,求叶子节点个数都做了详细的理解,以达到熟练的程度。

 

1,二叉树的结构定义:

typedef struct LNode 
{
	int data;   //节点的值
	LNode *Left; //指向做孩子
	LNode *Right;//指向右孩子
}*Tree;


 

2,二叉树的创建:采用递归前序建树,如果节点为空,则值为零,也就是虚节点,这里我为了简便。

 

//初始化二叉树
void CreateTree(Tree &L)
{
	LNode *p;
	int temp;
	
	cin>>temp;
	if(temp==0) L=NULL;
	else
	{
		L=(Tree)malloc(sizeof(LNode));
		L->Left=NULL;
		L->Right=NULL;
		L->data=temp;
		CreateTree(L->Left);//创建左孩子
		CreateTree(L->Right);//创建右孩子
	}
}


创建二叉树采用的先序序列,根——>左——>右 ,刚开始调用函数的时候传的参数(注意为什么要传引用?)是一个节点,如果这个节点值不为零,则这个节点存在,然后创建这个节点,then,创建左孩子CreateTree(L->Left),紧接着创建右孩子CreateTree(L->Right)

 

3,二叉树的三种顺序的遍历:

前序根——>左——>右

中序左——>根——>右

后序左——>右——>根

具体操作就看课本吧,直接实现代码,只有后序在非递归遍历的时候稍微麻烦一点

 

前序递归遍历

//前序递归遍历
void Pre(Tree T)
{
	if(T)
	{
		cout<<T->data<<" ";
		Pre(T->Left);
		Pre(T->Right);
	}
	else return ;
}

前序非递归遍历:

由于前序必须先遍历各节点之后才能使左孩子节点,然后才是右节点,我们不用递归这里只有用栈stack把,每走一步把气左孩子还有孩子先存入栈中,等根节点都遍历完之后,开始回溯遍历其左节点,,然后右节点,具体实现如下:


 

//前序非递归遍历
void Pre1(Tree T)
{
	stack<Tree> sqstack;
	Tree p;
	sqstack.push(T);
	while(!sqstack.empty())
	{
		p=sqstack.top();
		sqstack.pop();
		if(p)
		{
			cout<<p->data<<" ";
			sqstack.push(p->Right);
			sqstack.push(p->Left);
		}
	}
}


中序递归遍历

//中序递归遍历
void Mid(Tree T)
{
	if(T)
	{
		Mid(T->Left);
		cout<<T->data<<" ";
		Mid(T->Right);
	}
}


中序非递归遍历:

中序遍历必须先遍历左节点,然后根节点,所以我们必须先找到最后一个左节点,这个节点没有左节点,然后才能把它输出,输出之后,由于没有左节点,所以要遍历右节点,把有节点看作小二叉树的根节点,继续找最后的一个左节点,然后弹出栈并输出,从栈里取出的每个元素都一次这样操作,知道节点为空或者栈为空的时候,程序终止

//中序的非递归遍历
void Mid_N(Tree T)
{
	stack<Tree> sqstack;
	Tree p;
	p=T;
	if(!p) 
	{
		cout<<"树为空"<<endl;
		return ;
	}
	while(!sqstack.empty()||p!=NULL)
	{
		while(p)
		{
			sqstack.push(p);
			p=p->Left;
		}
		if(!sqstack.empty())
		{
			p=sqstack.top();
			sqstack.pop();
			cout<<p->data<<" ";
			p=p->Right;
		}
	}
}


后序递归遍历:

//后序递归遍历
void Back(Tree T)
{
	if(T)
	{
		Back(T->Left);
		Back(T->Right);
		cout<<T->data<<" ";
	}
}


后序非递归遍历:

我们依然用栈实现,只是这个时候,根节点在栈里可能两次被访问,但是此时如果没有遍历其右节点,根节点是不能出栈的,所以这里要做一下控制,我们定义了一个变量,用来存储上次访问的节点。然后我们分析一下当前节点可以出栈并输出的情况:当其左孩子和右孩子都为空的时候,或者上次访问的节点不为空,且为其左孩子节点或右孩子节点的时候,此时这个节点可以出栈。(这个可以想想为什么不是上次访问的节点只有是右孩子的时候才可以出栈?)

//后续非递归遍历
void Back_N(Tree T)
{
	stack<Tree> sqstack;
	Tree cur;
	Tree pre=NULL;
	sqstack.push(T);
	while(!sqstack.empty())
	{
		cur=sqstack.top();
		if((cur->Left==NULL&&cur->Right==NULL)||
			(pre!=NULL&&(pre==cur->Left||pre==cur->Right)))
		{
			cout<<cur->data<<" ";
			sqstack.pop();
			pre=cur;
		}
		else
		{
			if(cur->Right)
				sqstack.push(cur->Right);
			if(cur->Left)
				sqstack.push(cur->Left);
		}
	}
}


叶子节点的个数

也就是一个节点不为空,且其左孩子和右孩子都为空的节点的个数

//求叶子节点的个数
int Node_Sum(Tree T)
{
	static int sum=0;
	if(T->Left)
		Node_Sum(T->Left);
	if(T->Right)
		Node_Sum(T->Right);
	if(T->Left==NULL&&T->Right==NULL)
	{
		sum++;
		return sum;
	}
	return sum;
}

 

释放空间

开辟了空间肯定要释放的

//释放开辟的内存
void FreeTree(Tree &T)
{
	if(T)
	{
		FreeTree(T->Left);
		FreeTree(T->Right);
		free(T);
	}
}


完整代码贴出

//二叉树前中后,以及递归和非递归遍历

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;

typedef struct LNode 
{
	int data;   //节点的值
	LNode *Left; //指向做孩子
	LNode *Right;//指向右孩子
}*Tree;

//创建一棵二叉树L
void CreateTree(Tree &L)
{
	LNode *p;
	int temp;
	
	cin>>temp;
	if(temp==0) L=NULL;
	else
	{
		L=(Tree)malloc(sizeof(LNode));
		L->Left=NULL;
		L->Right=NULL;
		L->data=temp;
		CreateTree(L->Left);
		CreateTree(L->Right);
	}
}
//前序递归遍历
void Pre(Tree T)
{
	if(T)
	{
		cout<<T->data<<" ";
		Pre(T->Left);
		Pre(T->Right);
	}
	else return ;
}

//中序递归遍历
void Mid(Tree T)
{
	if(T)
	{
		Mid(T->Left);
		cout<<T->data<<" ";
		Mid(T->Right);
	}
}
//后序递归遍历
void Back(Tree T)
{
	if(T)
	{
		Back(T->Left);
		Back(T->Right);
		cout<<T->data<<" ";
	}
}
//前序非递归遍历
void Pre1(Tree T)
{
	stack<Tree> sqstack;
	Tree p;
	sqstack.push(T);
	while(!sqstack.empty())
	{
		p=sqstack.top();
		sqstack.pop();
		if(p)
		{
			cout<<p->data<<" ";
			sqstack.push(p->Right);
			sqstack.push(p->Left);
		}
	}
}
//中序的非递归遍历
void Mid_N(Tree T)
{
	stack<Tree> sqstack;
	Tree p;
	p=T;
	if(!p) 
	{
		cout<<"树为空"<<endl;
		return ;
	}
	while(!sqstack.empty()||p!=NULL)
	{
		while(p)
		{
			sqstack.push(p);
			p=p->Left;
		}
		if(!sqstack.empty())
		{
			p=sqstack.top();
			sqstack.pop();
			cout<<p->data<<" ";
			p=p->Right;
		}
	}
}

//后续非递归遍历
void Back_N(Tree T)
{
	stack<Tree> sqstack;
	Tree cur;
	Tree pre=NULL;
	sqstack.push(T);
	while(!sqstack.empty())
	{
		cur=sqstack.top();
		if((cur->Left==NULL&&cur->Right==NULL)||
			(pre!=NULL&&(pre==cur->Left||pre==cur->Right)))
		{
			cout<<cur->data<<" ";
			sqstack.pop();
			pre=cur;
		}
		else
		{
			if(cur->Right)
				sqstack.push(cur->Right);
			if(cur->Left)
				sqstack.push(cur->Left);
		}
	}
}
//求叶子节点的个数
int Node_Sum(Tree T)
{
	static int sum=0;
	if(T->Left)
		Node_Sum(T->Left);
	if(T->Right)
		Node_Sum(T->Right);
	if(T->Left==NULL&&T->Right==NULL)
	{
		sum++;
		return sum;
	}
	return sum;
}
//释放开辟的内存
void FreeTree(Tree &T)
{
	if(T)
	{
		FreeTree(T->Left);
		FreeTree(T->Right);
		free(T);
	}
}
int main()
{
	//stack<Tree> sqstack;
	Tree tree;
	CreateTree(tree); //建树
	cout<<"前序遍历"<<endl;
	Pre(tree);
	cout<<endl;
	Pre1(tree);
	cout<<endl;
	cout<<"中序遍历"<<endl;
	Mid(tree);             // 中序递归遍历
	cout<<endl;
	Mid_N(tree);     //中序非递归遍历
	cout<<endl;
	cout<<"后序递归遍历"<<endl;
	Back(tree);
	cout<<endl;
	cout<<"后序非递归遍历"<<endl;
	Back_N(tree);
	cout<<endl;
	cout<<"叶子节点的个数"<<endl;
	cout<<Node_Sum(tree)<<endl;
	FreeTree(tree);     //释放树
	return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值