欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

二叉树的非递归遍历

程序员文章站 2022-06-07 20:48:11
...

二叉树的非递归遍历

二叉树的遍历本质上其实就是入栈出栈的问题,二叉树的前序,中序,后序遍历都需要栈这个结构。

二叉树的建立

首先我们使用#创建法,建立一个二叉树代码如下:

BinaryNode* createTree(char* arr)
{
	static int i = 0;//设置一个静态变量,保证递归时能够顺利读取arr中的数据
	//这个i值可以是全局变量,也可用函数参数传入
	if (*(arr + i) == '#' || *(arr + i) == '\0')
	{
		if (*(arr + i) == '\0')
			return NULL;
		i++;
		return NULL;
	}
	BinaryNode* root = (BinaryNode*)malloc(sizeof(BinaryNode));
	root->ch = *(arr + i);
	i++;
	root->lchild = createTree(arr);
	root->rchild = createTree(arr);

	return root;
}

二叉树的非递归遍历
上图为所建立的二叉树结构。
先序遍历:先序遍历是先输出根节点,再输出左子树,最后输出右子树。上图的先序遍历结果就是:ABCDEF

中序遍历:中序遍历是先输出左子树,再输出根节点,最后输出右子树。上图的中序遍历结果就是:CBDAEF

后序遍历:后序遍历是先输出左子树,再输出右子树,最后输出根节点。上图的后序遍历结果就是:CDBFEA

二叉树的三种遍历

先序遍历
代码如下:

void Recur_Node(BinaryNode* root)
{
	if (root == NULL)
		return;
	BinaryNode* p = NULL;//保存从栈中弹出的树节点
	ListNode* temp = Init_List();//栈的初始化
	Push_Stack(temp,root);//首先让二叉树的头节点入栈
	while (temp->next != NULL)//判断栈是否为空
	{
		p = Pop_stack(temp);//将栈中元素取出并打印
		printf("%c", p->ch);
		if (p->rchild != NULL)
		{
			Push_Stack(temp, p->rchild);//先让右子树入栈
		}
		if (p->lchild != NULL)
		{
			Push_Stack(temp, p->lchild);//后让左子树入栈,使得首先遍历
			//的为左子树,下来为中间子树,最后为右子树
		}
	}
	free(temp);//释放栈
}

总的来说就是先让二叉树的头节点入栈,在循环中把栈是否为空作为二叉树遍历的终点,循环中先让右子树入栈后让左子树入栈,以此来满足先序遍历的条件。当栈为空时便意味着树已经遍历完成。
这个先序遍历和层次遍历代码极其相似,只需要改变一下入队顺序,并将栈结构改为队列便能进行层次遍历。

中序遍历
代码如下:

void InOrderNode(BinaryNode* root)
{
	if (root == NULL)
		return;
	ListNode* temp = Init_List();//初始化栈
	while (root != NULL || temp->next != NULL)//树节点不为空或栈不为空
	{
		while (root != NULL)
		{
			Push_Stack(temp,root);
			root = root->lchild;//让树节点走至左子树的最后一个NULL节点
		}
		if (!empty_stack(temp))//判断栈是否为空
		{
			root = Pop_stack(temp);//将栈中的一个元素取出,并赋值给root
			printf("%c", root->ch);
			root = root->rchild;//将右子树赋值给root
		}

	}
}

中序遍历便是先将所有左子树的节点入栈,之后,判断栈是否为空,不为空,则将栈中取出一节点,打印,并将此节点的右子树赋值给root。如此便能达到遍历左子树-》中间子树-》右子树。而当栈为空且树节点到了右子树的NULL处,便说明树已经遍历完成。

后序遍历
代码如下:

void PostOrderNode(BinaryNode* root)
{
	if (root == NULL)
		return;
	BinaryNode* p = NULL;//用于保存遍历过的节点
	BinaryNode* s = NULL;//用于保存栈顶元素
	ListNode* temp = Init_List();//栈的初始化
	do
	{
		while (root != NULL)
		{
			Push_Stack(temp, root);
			root = root->lchild;//将二叉树的所有左子树节点入栈
		}
		s = Get_Top(temp);//将栈顶元素赋值给s
		if (s->rchild == NULL || p == s->rchild)//当满足s的右子树为空
		//或者s的右节点为已遍历过的节点,输出s节点的值
		{
			Pop_stack(temp);
			printf("%c", s->ch);
			p = s;//p保存已遍历的s节点
		}
		else
		{
			root = s->rchild;//若未满足条件,则让其走向右子树
		}
	} while (temp->next != NULL);//栈是否为空
}

后序遍历方法有很多种,今天我写的是一种比较简单的方法。首先定义两个变量用来保存遍历过的节点和保存栈顶元素,利用这两个变量来判断是否遍历过右子树,以此来决定是否遍历中间子树。由于最后遍历中间子树的原因,所以只能利用栈为空的条件来做判断。

验证结果

二叉树的非递归遍历
代码验证过后也没有问题。