C语言 二叉树的遍历(前中后序递归与迭代遍历,层序迭代遍历)

前言

四种基本的遍历思想

  • 先(前)序遍历:根结点 ---> 左子树 ---> 右子树
  • 中序遍历:左子树---> 根结点 ---> 右子树
  • 后序遍历:左子树 ---> 右子树 ---> 根结点
  • 层次遍历:仅仅需按层次遍历就可以

如图所示二叉树

 先序遍历结果为:1 2 4 5 3 6

中序遍历结果为:4 2 5 1 6 3

后序遍历结果为:4 5 2 6 3 1

层序遍历结果为:1 2 3 4 5 6

递归的实现就是每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。

而迭代法遍历的原理就是模拟递归。

目录

四种基本的遍历思想

二叉树存储结构

 一、先序遍历

递归遍历

迭代遍历 

二、中序遍历

 递归遍历

 迭代遍历

三、后序遍历

 递归遍历

迭代遍历 

四、层序遍历


二叉树存储结构

typedef struct {
	int data;//数据域
	struct BiTNode* left, * right;//左子树右子树
}BiTNode, * BiTree;

 一、先序遍历

数据结构——二叉树先序、中序、后序及层次四种遍历(C语言版)_中序遍历_正弦定理的博客-CSDN博客

🍀递归遍历

算法C语言实现:

void PreOrderTraverse(BiTree T) {
	if (T != NULL) {
		printf("%d ", T->data);
		PreOrderTraverse(T->left);//递归遍历左子树
		PreOrderTraverse(T->right);//递归遍历右子树
	}
}

 🍀迭代遍历 

算法C语言实现: 

void PreOrderTraverse(BiTree T) {
	if (T == NULL)	return;
	BiTree Stack[100];
	int top = 0;
	Stack[top++] = T;//先把根结点入栈
	BiTree p = NULL;
	while (top > 0) {
		p = Stack[--top];//出栈
		printf("%d ", p->data);//打印结点值
		//将出栈结点非空子树入栈,一定是右子树先入栈,再左子树入栈
		//这样左子树就会先出栈
		if (p->right != NULL)	Stack[top++] = p->right;
		if (p->left != NULL)	Stack[top++] = p->left;
	}
}

 二、中序遍历

二叉树三种遍历(动态图+代码深入理解)-阿里云开发者社区

 🍂递归遍历

算法C语言实现:

void InOrderTraverse(BiTree T) {
	if (T != NULL) {
		PreOrderTraverse(T->left);//递归遍历左子树
		printf("%d ", T->data);
		PreOrderTraverse(T->right);//递归遍历右子树
	}
}

 🍂迭代遍历

算法C语言实现: 

void InOrderTraverse(BiTree T) {
	BiTree Stack[100];//定义个栈
	int top = 0;//栈顶指针
	BiTree root = T;//辅助指针
	while (top > 0 || root != NULL) {
		//搜索当前p指向结点的非空左子树并入栈
		if (root != NULL) {
			Stack[top++] = root;
			root = root->left;
		}
		//打印根节点(也就是中间结点)
		else {
			root = Stack[--top];
			printf("%d ", root->data);//弹出栈顶结点并打印
			root = root->right;//搜索p指向结点的右子树
		}

	}
}

还有种写法,原理相同循环语句有点不同而已。

void InOrderTraverse(BiTree T) {
	BiTree Stack[100];//定义个栈
	int top = 0;//栈顶指针
	BiTree root = T;//辅助指针
	while (top > 0 || root != NULL) {
		//搜索当前p指向结点的非空左子树并入栈
		while(root != NULL) {
			Stack[top++] = root;
			root = root->left;
		}
		//打印根节点(也就是中间结点)
			root = Stack[--top];
			printf("%d ", root->data);//弹出栈顶结点并打印
			root = root->right;//搜索p指向结点的右子树
		}
}

三、后序遍历

二叉树三种遍历(动态图+代码深入理解)-阿里云开发者社区

 🌿递归遍历

算法C语言实现:

void PostOrderTraverse(BiTree T) {
	if (T != NULL) {
		PreOrderTraverse(T->left);//递归遍历左子树
		PreOrderTraverse(T->right);//递归遍历右子树
		printf("%d ", T->data);
	}
}

 🌿迭代遍历 

和先序遍历类似,可以用一个数组储存遍历结果,最后反转就是左右中了。

void reverse(int* a, int asize) {
	int i, j, t;
	i = 0;
	j = asize - 1;
	while (i < j) {
		t = a[i];
		a[i] = a[j];
		a[j] = t;
		i++;
		j--;
	}
}
//后序遍历
void PostOrderTraverse(BiTree T) {
	if (T == NULL)	return;
	BiTree Stack[100];
	int top = 0;
	Stack[top++] = T;
	BiTree p = NULL;
	int result[100];//用来存放遍历结果
	int resultsize = 0;//记录长度
	while (top > 0) {
		p = Stack[--top];//出栈
		result[resultsize++] = p->data;
		//将出栈结点非空子树入栈,左子树先入栈,再右子树入栈
		//这样将结果反转就是左右中了
		if (p->left != NULL)	Stack[top++] = p->left;
		if (p->right != NULL)	Stack[top++] = p->right;
	}
	reverse(result, resultsize);//将结果反转
	//输出
	for (int i = 0; i < resultsize; i++) {
		printf("%d ", result[i]);
	}
}

其实这种方法遍历本质上还是前序遍历,只是把结果反转了,并不能称得上真正的后序遍历。 

以下这种后序遍历方法与前中序遍历不同的是借助了一个指针用来标记。

void PostOrderTraverse(BiTree T) {
	if (T == NULL)	return;
	BiTree Stack[100];
	int top = 0;
	BiTree prev = NULL;//用来标记,被标记的结点及其子树都是已经遍历完了的。
	BiTree root = T;//根节点指针
	while (top > 0 || root != NULL) {
		//把当前根节点入栈以及非空左子树入栈
		while (root != NULL) {
			Stack[top++] = root;
			root = root->left;
		}

		root = Stack[--top];//弹出左子树被完全遍历的结点

		//root->right==NULL当前根节点右子树为空,root->right==prev当前根节点右子树被完全遍历过
		if (root->right == NULL || root->right == prev) {
			printf("%d ", root->data);//左右子树都被遍历完,打印当前根节点值。
			prev = root;//标记当前根节点,用来判断后续结点的右子树是否被完全遍历。
			root = NULL;//根节点指针置空,为了回溯到父节点。
		}
		//将当前根节点入栈,遍历右子树
		else {
			Stack[top++] = root;
			root = root->right;
		}
	}

}

四、层序遍历

需要用队列作为辅助结构,我们先将根节点放到队列中,然后不断遍历队列。

首先拿出根节点,如果左子树/右子树不为空,就将他们放入队列中。第一遍处理完后,根节点已经从队列中拿走了,而根节点的两个孩子已放入队列中了,现在队列中就有两个节点 2 和 5。

 第二次处理,会将 2 和 5 这两个节点从队列中拿走,然后再将 2 和 5 的子节点放入队列中,现在队列中就有三个节点 346

我们把每层遍历到的节点都放入到一个结果集中,最后返回这个结果集就可以了。 

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>
//队列结点
typedef struct QNode {
	BiTree data;
	struct QNode* next;
}QNode;
//队列
typedef struct {
	QNode* front;
	QNode* rear;
	int n;//用来记录队列长度
}BiTQueue;
//队列入队操作
void Push(BiTQueue* Q, BiTree T) {
	QNode* node = malloc(sizeof(QNode));
	node->data = T;
	node->next = NULL;
	Q->rear->next = node;
	Q->rear = node;
	Q->n++;
}
//队列出队操作
BiTree Pop(BiTQueue* Q) {
	BiTree T = Q->front->next->data;
	if (Q->front->next == Q->rear)	Q->rear = Q->front;
	Q->front->next = Q->front->next->next;
	Q->n--;
	return T;
}
//层序遍历函数
void LeveOrderTraverse(BiTree T) {
	if (T == NULL)	return;
	BiTQueue* Q = InitQueue();//初始化队列
	BiTree p = NULL;
	Push(Q, T);//将根结点入队
	while (Q->n > 0) {
        //只取n个队列元素
		for (int i = Q->n; i > 0; i--) {
			p = Pop(Q);//出队
			printf("%d ", p->data);//打印结点值
			if (p->left != NULL)	Push(Q, p->left);//左子树入队
			if (p->right != NULL)	Push(Q, p->right);//右子树入队
		}
		printf("\n");
	}
}
  • 12
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Indifferent-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值