C语言-非递归完成树的三种遍历
1.前言
这一节我们来学习一下如何使用非递归的方式完成对树的遍历,废话不多说,放码过来!
- step1:构造二叉树
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10
typedef struct TreeNode {
int data;//数据域
struct TreeNode* left;//指向当前结点左子树的指针
struct TreeNode* right;//指向当前结点右子树的指针
}TreeNode;
- step2:构造结点,并建立联系(以下代码均在main函数中写)
TreeNode n1;
TreeNode n2;
TreeNode n3;
TreeNode n4;
n1.data = 1;
n2.data = 3;
n3.data = 5;
n4.data = 7;
n1.left = &n2;
n1.right = &n3;
n2.left = &n4;
n2.right = NULL;
n3.left = NULL;
n3.right = NULL;
n4.left = NULL;
n4.right = NULL;
接下来就是重头戏啦,如何非递归实现树的遍历,这里我们需要借助一个东西——栈
我们知道,栈是先进后出,利用这个特点,我们来试试如何遍历
1.前序遍历
我们首先让根节点入栈,即1入栈,然后将1出栈,随即访问其左右结点
由于前序遍历采取根左右,
故应先让右结点入栈,然后左结点入栈,
接下来左结点重复上述行为,先出栈,再访问其左右结点
有则入栈,没有就再出栈一个结点,重复上述过程
void PreOrderNonrecursion(TreeNode* T) {//先序非递归遍历
if (T == NULL)
return;
TreeNode* Stack[MaxSize];//创建一个栈
int top = -1;
TreeNode* p = NULL;//遍历指针
//思路:
/*
1.根节点入栈
2.先出栈一个元素,对其访问,判断其左右孩子是否存在
3.存在就入栈(顺序:右,左)==>可以保证出栈的时候是先左后右
*/
Stack[++top] = T;
while (top != -1) {//栈不为空
p = Stack[top--];
printf("%d ", p->data);
if (p->right != NULL)
Stack[++top] = p->right;
if (p->left != NULL)
Stack[++top] = p->left;
}
}
2.后序遍历
我们知道前序遍历是根左右,后序遍历是左右根,怎么建立联系呢?
我们试着将后序倒过来,就变成了根右左,你发现了什么?
写前序遍历的时候我们我们在访问节点时,先让右入栈,再让左入栈就是利用了栈的先进后出,那此时不就是先让左入栈,再让右入栈嘛,也就是说逆后序几乎和前序一模一样
我们先用一个栈完成逆后序,再用一个栈将逆后序依次出栈,不就实现后序了嘛!
void PostOrderNonrecursion(TreeNode* T) {//后序非递归遍历
if (T == NULL)
return;
TreeNode* Stack1[MaxSize];
int top1 = -1;
TreeNode* Stack2[MaxSize];
int top2 = -1;
TreeNode* p = NULL;//遍历指针
Stack1[++top1] = T;//根节点入栈
while (top1 != -1) {//栈不为空
p = Stack1[top1--];
Stack2[++top2] = p;
if (p->left != NULL)
Stack1[++top1] = p->left;
if (p->right != NULL)
Stack1[++top1] = p->right;
}
while (top2 != -1) {
p = Stack2[top2--];
printf("%d ", p->data);
}
}
3.中序遍历
- 从根节点开始,一直往左走,将途经的结点全部入栈
*直到不能往左走为止,此时出栈一个结点并访问
从这个结点开始,先往右走,再往左走,重复过程
这里空白不够大,我写不下,留给读者一些思考的空间
void InOrderNonrecursion(TreeNode* T) {//中序非递归遍历
//思路:
/*
* 从根节点开始,一直往左走,将途经的结点全部入栈
* 直到不能往左走为止,此时出栈一个结点并访问
* 从这个结点开始,先往右走,再往左走,重复过程
*
*/
if (T == NULL)
return;
TreeNode* Stack[MaxSize];
int top = -1;
TreeNode* p = NULL;
p = T;
while (top != -1 || p != NULL) {
while (p != NULL) {
Stack[++top] = p;
p = p->left;
}
if (top != -1) {
p = Stack[top--];
printf("%d ", p->data);
p = p->right;
}
}
}
附上全部代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10
typedef struct TreeNode {
int data;//数据域
struct TreeNode* left;//指向当前结点左子树的指针
struct TreeNode* right;//指向当前结点右子树的指针
}TreeNode;
void PreOrderNonrecursion(TreeNode* T) {//先序非递归遍历
if (T == NULL)
return;
TreeNode* Stack[MaxSize];//创建一个栈
int top = -1;
TreeNode* p = NULL;//遍历指针
//思路:
/*
1.根节点入栈
2.先出栈一个元素,对其访问,判断其左右孩子是否存在
3.存在就入栈(顺序:右,左)==>可以保证出栈的时候是先左后右
*/
Stack[++top] = T;
while (top != -1) {//栈不为空
p = Stack[top--];
printf("%d ", p->data);
if (p->right != NULL)
Stack[++top] = p->right;
if (p->left != NULL)
Stack[++top] = p->left;
}
}
void InOrderNonrecursion(TreeNode* T) {//中序非递归遍历
//思路:
/*
* 从根节点开始,一直往左走,将途经的结点全部入栈
* 直到不能往左走为止,此时出栈一个结点并访问
* 从这个结点开始,先往右走,再往左走,重复过程
*/
if (T == NULL)
return;
TreeNode* Stack[MaxSize];
int top = -1;
TreeNode* p = NULL;
p = T;
while (top != -1 || p != NULL) {
while (p != NULL) {
Stack[++top] = p;
p = p->left;
}
if (top != -1) {
p = Stack[top--];
printf("%d ", p->data);
p = p->right;
}
}
}
void PostOrderNonrecursion(TreeNode* T) {//后序非递归遍历
if (T == NULL)
return;
TreeNode* Stack1[MaxSize];
int top1 = -1;
TreeNode* Stack2[MaxSize];
int top2 = -1;
TreeNode* p = NULL;//遍历指针
Stack1[++top1] = T;//根节点入栈
while (top1 != -1) {//栈不为空
p = Stack1[top1--];
Stack2[++top2] = p;
if (p->left != NULL)
Stack1[++top1] = p->left;
if (p->right != NULL)
Stack1[++top1] = p->right;
}
while (top2 != -1) {
p = Stack2[top2--];
printf("%d ", p->data);
}
}
int main() {
TreeNode n1;
TreeNode n2;
TreeNode n3;
TreeNode n4;
n1.data = 1;
n2.data = 3;
n3.data = 5;
n4.data = 7;
n1.left = &n2;
n1.right = &n3;
n2.left = &n4;
n2.right = NULL;
n3.left = NULL;
n3.right = NULL;
n4.left = NULL;
n4.right = NULL;
printf("先序遍历为:");
PreOrderNonrecursion(&n1);
printf("\n");
printf("中序遍历为:");
InOrderNonrecursion(&n1);
printf("\n");
printf("后序遍历为:");
PostOrderNonrecursion(&n1);
return 0;
}
结束语
通过今天的学习,我相信小伙伴们应该可以理解非递归的遍历啦!其实只要你掌握了前序,后面的都可以类推,勤于思考,多动手敲代码,我们一起努力,持续更新…敬请期待