C语言-非递归完成树的三种遍历

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;
}

结束语

通过今天的学习,我相信小伙伴们应该可以理解非递归的遍历啦!其实只要你掌握了前序,后面的都可以类推,勤于思考,多动手敲代码,我们一起努力,持续更新…敬请期待
在这里插入图片描述

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值