废话不多说,先看看目录,了解本博客个大概,然后直接起飞、上干货!!!
一、图解四序遍历
在这里,不过多赘述,有前人写的非常优秀的博客,值得一看(链接如下)
这是我看过的最形象、简单、易懂、通彻的图解四序遍历,没有之一,博主动图做得非常好,别忘了给他收藏、点赞!(由于这博主没有给出层序遍历的代码,所以我稍作补充)
二、先前准备
1. 定义二叉树结点结构体
// 定义二叉树节点结构体
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode, * BiTree;
2. 通过键盘录入创建二叉树
输入案例:
8 7 5 1 -1 -1 -1 4 -1 -1 6 3 -1 -1 2 -1 -1
// 创建新的二叉树节点
void CreateBiTree(BiTree* T)
{ // 形参是 结点指针的指针 因为结点指针需要改变 所以使用指针
int x;
scanf("%d", &x); // 键盘录入
*T = (BiTree)malloc(sizeof(TreeNode));
if (x == -1)
*T = NULL; // 空结点
else if (x == '\n')
return; // 回车-创建结束-函数返回结束执行
else
{
if (!(*T))
exit(0);
(*T)->val = x; // 前序,输入
CreateBiTree(&(*T)->left); // 左结点指针的地址
CreateBiTree(&(*T)->right); // 右结点指针的地址
}
}
三、前序遍历
1. 递归式
// 前序遍历二叉树(递归)
void PreOrderTraverse(BiTree T)
{
if (T == NULL)
return;
printf("%d ", T->val);
PreOrderTraverse(T->left);
PreOrderTraverse(T->right);
}
2. 非递归式
// 前序遍历二叉树(非递归)
void PreorderTraversalIterative(BiTree T)
{ // 需要利用栈的知识
if (T == NULL)
return;
BiTree stack[1000]; // 创建 树-栈
int top = -1;
stack[++top] = T;
while (top >= 0) {
BiTree node = stack[top--];
printf("%d ", node->val);
if (node->right != NULL) // 先右后左
stack[++top] = node->right;
if (node->left != NULL) // @ 之所以 左结点后进栈,是因为,左结点必须先出栈,才能符合遍历的条件
stack[++top] = node->left;
}
}
四、中序遍历
1. 递归式
// 中序遍历二叉树(递归)
void InOrderTraverse(BiTree T)
{
if (T == NULL)
return;
InOrderTraverse(T->left);
printf("%d ", T->val);
InOrderTraverse(T->right);
}
2. 非递归式
// 中序遍历二叉树(非递归)
void InorderTraversalIterative(BiTree T) {
if (T == NULL)
return;
BiTree stack[1000];
int top = -1;
BiTree curr = T;
while (curr != NULL || top >= 0) {
while (curr != NULL) {
stack[++top] = curr;
curr = curr->left;
}
curr = stack[top--];
printf("%d ", curr->val);
curr = curr->right;
}
}
五、后序遍历
1. 递归式
// 后序遍历二叉树(递归)
void PostOrderTraverse(BiTree T)
{
if (T == NULL)
return;
PostOrderTraverse(T->left);
PostOrderTraverse(T->right);
printf("%d ", T->val);
}
2. 非递归式
// 后序遍历二叉树(非递归)
void PostorderTraversalIterative(BiTree T) {
if (T == NULL) {
return;
}
BiTree stack1[1000];
int top1 = -1;
BiTree stack2[1000];
int top2 = -1;
stack1[++top1] = T;
while (top1 >= 0) {
BiTree curr = stack1[top1--];
stack2[++top2] = curr;
if (curr->left != NULL) {
stack1[++top1] = curr->left;
}
if (curr->right != NULL) {
stack1[++top1] = curr->right;
}
}
while (top2 >= 0) {
BiTree node = stack2[top2--];
printf("%d ", node->val);
}
}
六、层序遍历
// 使用队列 层序遍历二叉树
void QueueLevelOrderTraversal(BiTree root) {
if (root == NULL) {
return;
}
// 创建一个队列来保存待访问的节点
// @ 其实并不是让结点入队列,本质上来说,是让每个结点的地址入队列
// @ 不然一个结点又有数据域,又有指针域,占这么大内存,怎么入队列呀
// @ 所以队列要开辟的空间,其实就是为 很多个 结点指针变量 开辟空间,所以这里是**,俩*
BiTree* queue = (BiTree*)malloc(sizeof(BiTree) * 1000);
int front = 0; // 队列的前指针,为什么初始化0,因为queue是指针数组,索引从0开始。
int rear = 0; // 队列的后指针
// 将根节点入队列
queue[rear++] = root;
while (front < rear) {
// 出队列并访问节点
BiTree node = queue[front++];
printf("%d ", node->val);
// 将左右子节点入队列
if (node->left) {
queue[rear++] = node->left; // @ 倒像是 “双指针”!!!
}
if (node->right) {
queue[rear++] = node->right;
}
}
// 释放队列内存
free(queue);
}
七、完整代码
#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode, * BiTree;
// 创建新的二叉树节点
void CreateBiTree(BiTree* T)
{ // 形参是 结点指针的指针 因为结点指针需要改变 所以使用指针
int x;
scanf("%d", &x); // 键盘录入
*T = (BiTree)malloc(sizeof(TreeNode));
if (x == -1)
*T = NULL; // 空结点
else if (x == '\n')
return; // 回车-创建结束-函数返回结束执行
else
{
if (!(*T))
exit(0);
(*T)->val = x; // 前序,输入
CreateBiTree(&(*T)->left); // 左结点指针的地址
CreateBiTree(&(*T)->right); // 右结点指针的地址
}
}
// 使用队列 层序遍历二叉树
void LevelOrderTraversal(BiTree root) {
if (root == NULL) {
return;
}
// 创建一个队列来保存待访问的节点
// @ 其实并不是让结点入队列,本质上来说,是让每个结点的地址入队列
// @ 不然一个结点又有数据域,又有指针域,占这么大内存,怎么入队列呀
// @ 所以队列要开辟的空间,其实就是为 很多个 结点指针变量 开辟空间,所以这里是**,俩*
BiTree* queue = (BiTree*)malloc(sizeof(BiTree) * 1000);
int front = 0; // 队列的前指针,为什么初始化0,因为queue是指针数组,索引从0开始。
int rear = 0; // 队列的后指针
// 将根节点入队列
queue[rear++] = root;
while (front < rear) {
// 出队列并访问节点
BiTree node = queue[front++];
printf("%d ", node->val);
// 将左右子节点入队列
if (node->left) {
queue[rear++] = node->left; // @ 倒像是 “双指针”!!!
}
if (node->right) {
queue[rear++] = node->right;
}
}
// 释放队列内存
free(queue);
}
// 前序遍历二叉树(递归)
void PreOrderTraverse(BiTree T)
{
if (T == NULL)
return;
printf("%d ", T->val);
PreOrderTraverse(T->left);
PreOrderTraverse(T->right);
}
// 中序遍历二叉树(递归)
void InOrderTraverse(BiTree T)
{
if (!T)
return;
InOrderTraverse(T->left);
printf("%d ", T->val);
InOrderTraverse(T->right);
}
// 后序遍历二叉树(递归)
void PostOrderTraverse(BiTree T)
{
if (T == NULL)
return;
PostOrderTraverse(T->left);
PostOrderTraverse(T->right);
printf("%d ", T->val);
}
// 先序遍历二叉树(非递归)
void PreorderTraversalIterative(BiTree T)
{ // @ 利用栈的知识,重要,必须掌握!!!
if (T == NULL)
return;
BiTree stack[1000]; // 创建 树-栈
int top = -1;
stack[++top] = T;
while (top >= 0) {
BiTree node = stack[top--];
printf("%d ", node->val);
if (node->right != NULL) // 先右后左
stack[++top] = node->right;
if (node->left != NULL) // @ 之所以 左结点后进栈,是因为,左结点必须先出栈,才能符合遍历的条件
stack[++top] = node->left;
}
}
// 中序遍历二叉树(非递归)
void InorderTraversalIterative(BiTree T) {
if (T == NULL)
return;
BiTree stack[1000];
int top = -1;
BiTree curr = T;
while (curr != NULL || top >= 0) {
while (curr != NULL) {
stack[++top] = curr;
curr = curr->left;
}
curr = stack[top--];
printf("%d ", curr->val);
curr = curr->right;
}
}
// 后序遍历二叉树(非递归)
void PostorderTraversalIterative(BiTree T) {
if (T == NULL) {
return;
}
BiTree stack1[1000];
int top1 = -1;
BiTree stack2[1000];
int top2 = -1;
stack1[++top1] = T;
while (top1 >= 0) {
BiTree curr = stack1[top1--];
stack2[++top2] = curr;
if (curr->left != NULL) {
stack1[++top1] = curr->left;
}
if (curr->right != NULL) {
stack1[++top1] = curr->right;
}
}
while (top2 >= 0) {
BiTree node = stack2[top2--];
printf("%d ", node->val);
}
}
int main() {
// 构建一个二叉树
BiTree T;
CreateBiTree(&T); // 实参为 根结点指针的地址
// 层序遍历二叉树
printf("层序遍历结果:");
LevelOrderTraversal(T);
printf("\n");
for (int i = 0; i < 10; i++)
printf("**");
printf("递归式 前中后 三序遍历");
for (int i = 0; i < 10; i++)
printf("**");
printf("\n");
printf("递归式前序遍历二叉树:");
PreOrderTraverse(T);
printf("\n");
printf("递归式中序遍历二叉树:");
InOrderTraverse(T);
printf("\n");
printf("递归式后序遍历二叉树:");
PostOrderTraverse(T);
printf("\n");
for (int i = 0; i < 10; i++)
printf("**");
printf("非递归式 前中后 三序遍历");
for (int i = 0; i < 10; i++)
printf("**");
printf("\n");
printf("前序遍历二叉树(非递归):");
PreorderTraversalIterative(T);
printf("\n");
printf("中序遍历二叉树(非递归):");
InorderTraversalIterative(T);
printf("\n");
printf("后序遍历二叉树(非递归):");
PostorderTraversalIterative(T);
printf("\n");
return 0;
}
制作不易,能点个赞支持一下吗,您的鼓励,是我前行的最大动力!