【数据结构】二叉树的非递归遍历(完整代码)

本文详细介绍了如何使用非递归方法遍历二叉树,包括前序、中序和后序遍历的具体步骤及代码实现,通过栈操作实现遍历流程,适用于深入理解二叉树的数据结构。

默认给一棵树前序遍历的结果,按要求创建这棵树(#表示空),并用非递归的方法对它进行遍历。

解题思路

1.递归遍历: 则将二叉树的遍历看作是分治问题,将每一棵树都分为根-左子树-右子树三部分,每部分按同样的方法递归遍历即可。具体实现见下篇博客 二叉树的实现&递归遍历
2.非递归遍历:我们可以借用栈的知识完成树的遍历。使用栈完成的过程以下面的前序遍历为例

前序: 根–> 左–> 右
主要思路:若根节点有效则输出并入栈;访问其左子树遇到根节点输出并入栈直到根节点下再无左子树,将栈顶元素出栈,并继续访问它的右子树;直至栈内无元素且当前元素无效,遍历结束。
具体过程如下:

1.根节点A有效则输出并入栈,访问A左树(输出条件:当前根节点有效;也是入栈条件)
2.B有效则输出并入栈,访问B左树
3.D有效则输出并入栈,访问D左树
4.D左树为空,当前栈顶D出栈,访问D右树(出栈条件:左树/右树 为空,栈顶元素出栈)
5.D右树为空,当前栈顶B出栈,访问B右树
6.E有效则输出并入栈,访问E左树
7.E左树为空,当前栈顶E出栈,访问E右树
8.F有效则输出并入栈,访问F左树
9.F左树为空,当前栈顶F出栈,访问F右树
10.F右树为空,当前栈顶A出栈,访问A右树
11.C有效则输出并入栈,访问C左树
12.C左树为空,当前栈顶C出栈,访问C右树
13.C右树为空,栈内无元素 (结束条件:栈内无元素,或者当前元素为空)
遍历结束!!

在这里插入图片描述

实现前序的代码如下所示:

//前序:A  B  D  E  F  C
while (StackEmpty(&st) != 0 || cur != NULL)  //循环条件:与(栈内无元素,或者当前元素为空)相反
{
	while (cur != NULL)  //输出/入栈条件:当前节点不为空
	{
		printf("%c ", cur->_data);  //输出
		StackPush(&st, cur);  //入栈
		cur = cur->_left;  //访问节点左子树
	}
	BTNode* top = StackTop(&st);  //找到栈顶元素
	StackPop(&st);   /出栈条件:左树/右树 为空,栈顶元素出栈
	cur = top->_right;  //访问右子树
}

中序: 左 --> 根 --> 右

//中序:D  B  E  F  A  C
while (StackEmpty(&st) != 0 || cur != NULL) //当栈不为空或当前节点有效,循环继续
	{
		while (cur != NULL)  //当前节点不为空
		{
			StackPush(&st, cur); //节点入栈
			cur = cur->_left;  //访问左子树
		}
		BTNode* top = StackTop(&st);  //找到栈顶元素
		printf("%c ", top->_data);  //输出栈顶元素
		StackPop(&st);  //栈顶元素出栈
		cur = top->_right;  //访问右子树
	}

后序: 左 --> 右 --> 根
注意:要判断此时访问的结点之前是否访问过!!

//后序:D  F  E  B  C  A
BTNode* prev = NULL;
while (cur || StackEmpty(&st) != 0)
	{
		while (cur != NULL)
		{
			StackPush(&st, cur);  //入栈
			cur = cur->_left;  //访问左子树
		}
		BTNode* top = StackTop(&st);
		if (top->_right == NULL || top->_right == prev) //右子树为空,或者已经访问过
		{
			StackPop(&st);  //栈顶元素出栈
			printf("%c ", top->_data); //输出
			prev = top;
		}
		else cur = top->_right;
	}
完整代码
BT.h – 头文件
#define _CRT_SECURE_NO_WARNINGS 1
#ifndef __TREE_H__
#define __TREE_H__ 

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>

typedef char BTDataType;
typedef struct BinaryTreeNode   //树节点定义
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

//创建树
BTNode *BinaryTreeCreate(BTDataType*a, int*pi);
//销毁树
void BinaryTreeDestory(BTNode* root);
//非递归遍历
void BinaryPrevOrder(BTNode* root);  //前序
void BinaryInOrder(BTNode* root);   //中序
void BinaryPostOrder(BTNode* root);   //后序
//测试类
void Test();

typedef BTNode* STDataType;
typedef struct Stack   //栈定义
{
	STDataType* _a;
	int _top;
	int _capacity;
}Stack;

//栈的操作
void StackInit(Stack* ps);  //初始化
void StackDestory(Stack* ps);  //销毁
void StackPush(Stack *ps, STDataType x);  //入栈
void StackPop(Stack* ps);  //出栈
STDataType  StackTop(Stack* ps);  //取栈顶元素
int StackEmpty(Stack* ps); //判断栈空
int StackSize(Stack* ps);  //判断栈内元素
void StackPrint(Stack* ps);   //栈节点输出

#endif//__TREE_H__
BT.c – 树的操作
#define _CRT_SECURE_NO_WARNINGS 1
#include "BT.h"

BTNode *BinaryTreeCreate(BTDataType*a, int* pi)  //创建树
{
	if (a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->_left = root->_right = NULL;
	root->_data = a[*pi];
	(*pi)++;
	root->_left = BinaryTreeCreate(a, pi);
	root->_right = BinaryTreeCreate(a, pi);
	return root;
}

void BinaryTreeDestory(BTNode* root)  //销毁树
{
	if (root)
	{
		BinaryTreeDestory(root->_left);
		BinaryTreeDestory(root->_right);
		free(root);
		root = NULL;
	}
}

void BinaryPrevOrder(BTNode* root)  //前序遍历
{
	Stack st;
	StackInit(&st);
	BTNode* cur = root;
	while (StackEmpty(&st) != 0 || cur != NULL)
	{
		while (cur != NULL)
		{
			printf("%c ", cur->_data);
			StackPush(&st, cur);
			cur = cur->_left;
		}
		BTNode* top = StackTop(&st);
		StackPop(&st);
		cur = top->_right;
	}
}

void BinaryInOrder(BTNode* root)  //中序遍历
{
	Stack st;
	StackInit(&st);
	BTNode* cur = root;
	while (StackEmpty(&st) != 0 || cur != NULL)
	{
		while (cur != NULL)
		{
			StackPush(&st, cur);
			cur = cur->_left;
		}
		BTNode* top = StackTop(&st);
		printf("%c ", top->_data);
		StackPop(&st);
		cur = top->_right;
	}
}

void BinaryPostOrder(BTNode* root)  //后序遍历
{
	BTNode* cur = root;
	BTNode* prev = NULL;
	Stack st;
	StackInit(&st);
	while (cur || StackEmpty(&st) != 0)
	{
		while (cur != NULL)
		{
			StackPush(&st, cur);
			cur = cur->_left;
		}
		BTNode* top = StackTop(&st);
		if (top->_right == NULL || top->_right == prev)
		{
			StackPop(&st);
			printf("%c ", top->_data);
			prev = top;
		}
		else cur = top->_right;
	}
}


void Test()  //测试
{
	char a[20] = "ABD##E#H##CF##G##";
	int pi = 0;
	int i = 0;
	BTNode* root = BinaryTreeCreate(a, &pi);
	printf("树创建成功!\n");
	printf("树前序遍历的结果是: ");
	BinaryPrevOrder(root);
	printf("\n");
	printf("树中序遍历的结果是: ");
	BinaryInOrder(root);
	printf("\n");
	printf("树后序遍历的结果是: ");
	BinaryPostOrder(root);
	printf("\n");
	BinaryTreeDestory(root);
	printf("销毁成功!\n");
}
ST.c – 栈的操作
#define _CRT_SECURE_NO_WARNINGS 1
#include "BT.h"

void StackInit(Stack* ps)  //栈的初始化
{
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0;
}

void StackDestory(Stack* ps)  //栈的销毁
{
	assert(ps);
	ps->_capacity = 0;
	ps->_top = 0;
	free(ps->_a);
	ps->_a = NULL;
}

void StackPush(Stack *ps, STDataType x)  //入栈
{
	assert(ps);
	if (ps->_top == ps->_capacity)
	{
		size_t newcapacity = (ps->_capacity == 0 ? 4 : ps->_capacity * 2);
		ps->_a = (STDataType*)realloc(ps->_a, sizeof(STDataType)*newcapacity);
		ps->_capacity = newcapacity;
	}
	ps->_a[ps->_top] = x;
	ps->_top++;
}

void StackPop(Stack* ps)  //出栈
{
	assert(ps&&ps->_top>0);
	ps->_top--;
}

STDataType  StackTop(Stack* ps)  //取栈顶元素
{
	assert(ps&&ps->_top>0);
	return ps->_a[ps->_top - 1];
}

int StackEmpty(Stack* ps)  //判断栈是否为空
{
	assert(ps);
	if (ps->_top == 0)
		return 0;
	else return 1;
}

int StackSize(Stack* ps)  //判断栈内元素
{
	assert(ps);
	STDataType size = ps->_top;
	return size;
}

void StackPrint(Stack* ps)  //输出栈内元素
{
	assert(ps);
	while (StackEmpty(ps) != 0)
	{
		printf("%d ", StackTop(ps));
		StackPop(ps);
	}
	printf("\n");
}
main.c – 主文件
#define _CRT_SECURE_NO_WARNINGS 1
#include "BT.h"

int main()
{
	printf("      *******二叉树的实现******\n");
	Test();
	printf("\n");
	system("pause");
	return 0;
}
### 数据结构 二叉树非递归遍历算法实现 #### 前序遍历(根左右) 前序遍历可以通过栈来模拟递归调用的过程。每次访问一个节点时,先处理该节点的数据,再依次将其右子树和左子树压入栈中。 ```cpp void preOrderTraversalNonRecursive(Tree root) { if (!root) return; std::stack<Node*> s; Node *current = root; while (current || !s.empty()) { while (current) { printf("%c ", current->data); s.push(current); current = current->left; } current = s.top(); s.pop(); current = current->right; } } ``` #### 中序遍历(左根右) 对于中序遍历,在访问当前节点之前需要先完全遍历其左子树。因此可以一直向左走直到最左边的叶子结点,并在此过程中将沿途遇到的所有节点都加入到栈里;当无法继续往更深处前进之后,则回溯并打印最近一次被存放在堆栈中的那个元素,接着转向它的右侧分支重复上述过程直至整棵树都被扫描完毕为止[^1]。 ```cpp void inOrderTraversalNonRecursive(Tree root) { if (!root) return; std::stack<Node*> s; Node *current = root; while (current || !s.empty()) { while (current) { s.push(current); current = current->left; } current = s.top(); s.pop(); printf("%c ", current->data); current = current->right; } } ``` #### 后序遍历(左右根) 后序遍历相对复杂一些,因为要确保父节点是在两个孩子都被访问过后才输出。为此可以在定义 `Node` 类型的时候增加一个布尔成员变量 `ok` 来标记是否已经完成了左侧孩子的遍历工作。这样就可以利用这个标志位区分何时应该输出某个特定位置上的值了。 ```cpp void postOrderTraversalNonRecursive(Tree root) { if (!root) return; std::stack<Node*> s; Node *current = root; Node *prev = nullptr; do { while (current) { s.push(current); current = current->left ? current->left : current->right; } while (!s.empty() && ((current = s.top())->right == prev || !current->right)) { printf("%c ", current->data); s.pop(); prev = current; } if (!s.empty()) current = s.top()->right; else current = nullptr; } while (!s.empty() || current); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值