二叉树的三种遍历(前序,中序,后序),递归与非递归表示,(初中生表示看完就懂了)

二叉树的三种遍历

对如图二叉树我们分别用前序,中序,后续三种遍历
在这里插入图片描述

递归表示

前序

首先访问根,再先序遍历左(右)子树,最后先序遍历右(左)子树

代码实现如下

void PreOrderTraversal(BinTree *BT)
{
	if(*BT)
	{
		printf("%d",BT->Data);
		PreOrderTraversal(BT->Left);
		PreOrderTraversal(BT->Right);
	}
}

在这里插入图片描述
根据路径,第一次遇见的节点输出
那么此时根据递归的思想,输出的节点应该是
A B D E H C F I G

中序

首先中序遍历左(右)子树,再访问根,最后中序遍历右(左)子树

void PreOrderTraversal(BinTree *BT)
{
	if(*BT)
	{
		PreOrderTraversal(BT->Left);
		printf("%d",BT->Data);
		PreOrderTraversal(BT->Right);
	}
}

在这里插入图片描述
根据路径,第二次遇见的节点输出
输出的节点是
D B H E A F I C G
同时你会发现表达方式也就是printf 的位置换了下

后序

首先后序遍历左(右)子树,再后序遍历右(左)子树,最后访问根
根据前序和中序,后序是不是很容易出来了

void PreOrderTraversal(BinTree *BT)
{
	if(*BT)
	{
		PreOrderTraversal(BT->Left);
		PreOrderTraversal(BT->Right);
		printf("%d",BT->Data);
	}
}

在这里插入图片描述
根据路径,第三次遇见的节点输出
输出为
D H B E I F G C A

分析

前序,中序,后序遍历,所经过节点的路线是一模一样的,只是访问的时机不同
在这里插入图片描述
所以根据图来分析
从入口到出口,分别用 蓝色正方形 、 绿色椭圆形 、 红色圆角矩形 来表示先序、中序、后序访问各节点的时刻

PS:我所用用的遍历均是先向走,在向右的

遍历的非递归表示(栈)

前序的非递归实现

前序遍历的顺序是根-左-右

void PreOrderTraversal(BinTree *BT)
{
	if (!BT)
		return;
	BinTree *P = BT;
	stack<BinTree*>st;
	while (P != NULL || !st.empty())
	{
		while (P)
		{
			st.push(P);
			cout << P->Value << endl;
			P = P->Left;
		}
		if (!st.empty())
		{
			P = st.top();
			st.pop();
			P = P->Right;
		}

	}
}

中序的非递归实现

中序的顺序是左-根-右
思路:

  1. 遇到一个节点先压入栈,并遍历他的左子树
  2. 当左子树遍历后,从栈顶弹出这个节点并访问
  3. 然后按其右指针,再去中序遍历该节点的右子树
void PreOrderTraversal(BinTree *BT)
{
	if (!BT)
		return;
	BinTree *P = BT;
	stack<BinTree*>st;
	while (P != NULL || !st.empty())
	{
		while (P)//一直向左并将沿途节点压入栈
		{
			st.push(P);
			P = P->Left;
		}
		if (!st.empty())
		{
			P = st.top();
			cout << P->Value << endl; 
			st.pop();
			P = P->Right;//向右访问右子树
		}

	}
}

后序遍历的非递归实现

后序的顺序是左-右-根
我认为后序遍历非递归的思路是三个中最难的,
因为后序非递归遍历二叉树的顺序是先访问左子树,再访问右子树,最后访问根节点。当用堆栈来存储节点,必须分清返回根节点时,是从左子树返回的,还从右子树返回的。所以,使用辅助指针Flag,其指向最近访问过的节点。也可以在节点中增加一个标志域,记录是否已被访问

void PreOrderTraversal(BinTree *BT)
{
	if (!BT)
		return;
	BinTree *P = BT,*Flag = NULL;
	stack<BinTree*>st;
	while (P != NULL || !st.empty())
	{
		if(P)//走到最左边
		{
			st.push(P);
			P = P->Left;
		}
		else
		{
			P = st.top();
			if(P->Right != NULL && P->Right != Flag)//右子树存在,并且未被访问
			{
				P = P->Right;
			}
			else
			{
				st.pop();
				cout << P->value << endl;
				Flag = P;
				P = NULL;
			}
		}

	}
}

因初学数据结构,若有错误,欢迎指出

猜你喜欢

转载自blog.csdn.net/leowahaha/article/details/107404424
今日推荐