【数据结构】非递归实现二叉树的前 + 中 + 后 + 层序遍历(听说面试会考?)

在这里插入图片描述

👦个人主页:@Weraphael
✍🏻作者简介:目前学习C++和算法
✈️专栏:数据结构
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨


目录

  • 一、需要使用到的代码
      • 1.1 二叉树的基本实现
      • 1.2 栈
      • 1.3 队列
  • 二、非递归实现二叉树的前序遍历
      • 2.1 思路
      • 2.2 代码实现
  • 三、非递归实现二叉树的前序遍历
      • 3.1 思路
      • 3.2 代码实现
  • 四、后序遍历
      • 4.1 思路
      • 4.2 代码实现
  • 五、层序遍历
      • 5.1 思路
      • 5.2 代码实现
      • 5.3 整个测试结果
  • 六、总结

一、需要使用到的代码

1.1 二叉树的基本实现

二叉树的基本实现在以往博客已经详细讨论过了,这里直接给出本篇博客的所需用到的源代码。【数据结构】二叉树的链式结构(笔记总结)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>typedef int DataType;typedef struct BinaryTree
{DataType _data;struct BinaryTree *_left;struct BinaryTree *_right;
} BinaryTree;// 创建结点
BinaryTree *CreateNode(DataType x)
{BinaryTree *newnode = (BinaryTree *)malloc(sizeof(BinaryTree));if (newnode == NULL){printf("CreateNode failed\n");return NULL;}newnode->_left = NULL;newnode->_right = NULL;newnode->_data = x;return newnode;
}// 建树
BinaryTree *CreateTree()
{// 假定树的模型如下所示//    1//  2   3// 4  5    6BinaryTree *node1 = CreateNode(1);BinaryTree *node2 = CreateNode(2);BinaryTree *node3 = CreateNode(3);BinaryTree *node4 = CreateNode(4);BinaryTree *node5 = CreateNode(5);BinaryTree *node6 = CreateNode(6);node1->_left = node2;node1->_right = node3;node2->_left = node4;node2->_right = node5;node3->_right = node6;return node1;
}// 递归实现前序遍历
void PreOrder(BinaryTree *root)
{if (root == NULL)return;printf("%d ", root->_data);PreOrder(root->_left);PreOrder(root->_right);
}// 递归实现中序遍历
void InOrder(BinaryTree *root)
{if (root == NULL)return;InOrder(root->_left);printf("%d ", root->_data);InOrder(root->_right);
}// 递归实现后序遍历
void PostOrder(BinaryTree *root)
{if (root == NULL)return;PostOrder(root->_left);PostOrder(root->_right);printf("%d ", root->_data);
}

在以上源代码中,我另外给出了递归实现遍历的版本,目的是为了和非递归(迭代)版进行对比。

1.2 栈

// 需要存储的数据类型是二叉树结构体的指针!
typedef BinaryTree *DataType1;typedef struct stack
{DataType1 *_a;int size;int capacity;
} stack;void StackInit(stack *st)
{st->_a = (DataType1 *)malloc(sizeof(DataType1) * 4); // 假设默认大小为4if (st->_a == NULL){printf("st->_a malloc failed\n");return;}st->capacity = 4;st->size = 0;
}// 入栈
void PushStack(stack *st, DataType1 val)
{if (st->capacity == st->size){// 每次扩大两倍DataType1 *newcapacity = (DataType1 *)realloc(st->_a, sizeof(DataType1) * 4 * 2); if (newcapacity == NULL){printf("st->_a realloc failed\n");return;}st->_a = newcapacity;st->capacity *= 2;}st->_a[st->size] = val;st->size++;
}// 判断栈是否为空
bool StackEmpty(stack *st)
{return st->size == 0;
}// 出栈
void PopStack(stack *st)
{if (StackEmpty(st)){printf("stack is empty\n");return;}st->size--;
}// 访问栈顶元素
DataType1 StackTop(stack *st)
{return st->_a[st->size - 1];
}

栈是后面前、中、后序遍历所需要的。但是需要注意的是:栈需要存储的数据类型是二叉树结构体的指针。为什么?在后面会详细说明。

1.3 队列

// 需要存储的数据类型是二叉树结构体的指针
typedef BinaryTree *QueueType;
typedef struct QueueNode
{QueueType _val;struct QueueNode *_next;
} QueueNode;typedef struct Queue
{QueueNode *tail;QueueNode *head;
} Queue;// 初始化队列
void InitQueue(Queue *q)
{q->tail = q->head = NULL;
}// 插入元素
void PushQueue(Queue *q, QueueType x)
{QueueNode *newnode = (QueueNode *)malloc(sizeof(QueueNode));if (newnode == NULL){printf("newnode create failed\n");return;}newnode->_next = NULL;newnode->_val = x;if (q->head == NULL){if (q->tail != NULL)return;q->head = q->tail = newnode;}else{q->tail->_next = newnode;q->tail = newnode;}
}// 判断队列是否为空
bool QueueEmpty(Queue *q)
{return (q->head == NULL) && (q->tail == NULL);
}// 队头元素
QueueType FrontQueue(Queue *q)
{return q->head->_val;
}// 出队列
void PopQueue(Queue *q)
{if (QueueEmpty(q)){printf("Queue is empty\n");return;}if (q->head->_next == NULL){free(q->head);q->head = q->tail = NULL;}else{QueueNode *next = q->head->_next;free(q->head);q->head = next;}
}

队列是为层序遍历所准备的同理地,队列存储的数据类型同样也要是二叉树结构体指针。

为了快速实现二叉树的遍历,以上栈和队列的细节代码并不完整。详细的可以参考往期博客:点击跳转

话不多说,现在进入正题!

二、非递归实现二叉树的前序遍历

2.1 思路

请看下图

在这里插入图片描述

最后回过头来讲讲为什么栈的存储的类型要是二叉树结构体的指针?

通过上图,我们总结了:结点出栈,需要带入其左右孩子。因此,如果不是其结构体指针,那么也就无法将root的左右孩子入栈了。注意:也不能存结构体。因为一个结构体太大了,而指针的大小只有4/8字节

2.2 代码实现

// 非递归实现前序遍历
void PreOrder_nonR(BinaryTree *root)
{// 1. 需要一个赋值栈stack st;StackInit(&st);// 2. 如果根结点不为空入栈if (root != NULL){PushStack(&st, root);}while (!StackEmpty(&st)){// 记录栈顶元素BinaryTree *top = StackTop(&st);// 3. 出栈后带入其左右孩子PopStack(&st);printf("%d ", top->_data);// !要注意顺序:先带右孩子,再带左孩子 if (top->_right)PushStack(&st, top->_right);if (top->_left)PushStack(&st, top->_left);}
}

三、非递归实现二叉树的前序遍历

3.1 思路

请看下图

在这里插入图片描述

3.2 代码实现

void InOrder_nonR(BinaryTree *root)
{// 1. 需要一个辅助栈stack st;StackInit(&st);// 如果一开始根结点为NULL// 直接返回if (root == 0)return;// 2.遍历左孩子,将其全部入栈BinaryTree *cur = root;while (cur){PushStack(&st, cur);cur = cur->_left;}while (!StackEmpty(&st)){// 出栈打印BinaryTree *top = StackTop(&st);PopStack(&st);printf("%d ", top->_data);// 特判:出栈结点存在右孩子if (top->_right){// 将其入栈PushStack(&st, top->_right);// 然后还要特殊判断这个右孩子有没有左孩子// 因为我们要保证 先左 再根 再右BinaryTree *cur2 = top->_right;while (cur2->_left){PushStack(&st, cur2->_left);cur2 = cur2->_left;}}}
}

四、后序遍历

4.1 思路

后序遍历我就不画图了,本人一开始写非递归后序遍历写了好久,都失败了(太菜了)。直到我看到一个视频,才知道原来后序遍历这么简单!

首先可以参考前序遍历(根左右)。因此,我们只要将前序遍历的代码逻辑的遍历顺序左和右对调一下,就变成根右左,最后再对其逆序,就是左右根,也就是后序遍历的结果了

4.2 代码实现

void PostOrder_nonR(BinaryTree *root)
{int res[6]; // 为了逆序int i = 0; // 用于遍历res数组memset(res, 0, sizeof(int));stack st;StackInit(&st);if (root != NULL){PushStack(&st, root);}while (!StackEmpty(&st)){BinaryTree *top = StackTop(&st);PopStack(&st);res[i++] = top->_data;// 将前序遍历的代码逻辑的遍历顺序对调if (top->_left)PushStack(&st, top->_left);if (top->_right)PushStack(&st, top->_right);}// 最后逆序输出即可for (int k = i - 1; k >= 0; k--){printf("%d ", res[k]);}printf("\n");
}

五、层序遍历

5.1 思路

层序遍历顾名思义就是一层一层遍历,那么就不能使用栈,得使用队列。

步骤:使用一个队列,出一个结点,带入它的孩子结点

  • 如果树不为空,就先让根结点入队列
    在这里插入图片描述

  • 然后出队列(打印1),再把1的左孩子和右孩子带入队列
    在这里插入图片描述

  • 接着让2出队列,再把2的孩子入队列
    在这里插入图片描述

  • 同理,再让4出队列,把它的孩子入队列
    在这里插入图片描述

  • 最后如果队列为空,即完成层序遍历
    在这里插入图片描述

5.2 代码实现

void LevelOrder(BinaryTree *root)
{// 1. 需要辅助队列Queue q;InitQueue(&q);// 如果一开始根结点root不为空// 则入队列if (root != NULL)PushQueue(&q, root);// 然后出双亲结点,带入子结点while (!QueueEmpty(&q)){BinaryTree *front = FrontQueue(&q);PopQueue(&q);printf("%d ", front->_data);// 带入子结点if (front->_left)PushQueue(&q, front->_left);if (front->_right)PushQueue(&q, front->_right);}
}

5.3 整个测试结果

在这里插入图片描述

六、总结

对于数据结构,还是得建议多画画图。最后我不将所有的代码整合到一块,读者只需理解,最好自己实现一遍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/190496.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第2关:还原键盘输入(list)

题目&#xff1a; 知识点&#xff1a; 列表list相较于数组&#xff1a; 优势&#xff1a;可在任意指定位置插入或者删除元素而不影响列表其他地方 。 劣势&#xff1a;无法直接进行下标索引&#xff0c;需要迭代器it逐个遍历。 代码&#xff1a; #include <iostream>…

Mysql学习笔记--基础

一&#xff0c;SQL最重要的增删改命令格式 1&#xff0c;insert into 表名&#xff08;不写这个括号里面的内容就默认所有字段都要添加&#xff09; values&#xff08;&#xff09; 插入单条数据 2&#xff0c;insert into 表名 (里面是列名) values&#xff08;根据列名依次…

Git之分支与版本->课程目标及知识点的应用场景,分支的场景应用,标签的场景应用

1.课程目标及知识点的应用场景 Git分支和标签的命名规范 分支 dev/test/pre/pro(即master) dev:开发环境--windows (自己的电脑) test:测试环境--windows/linux (公司专门的测试电脑 pre:灰度环境(非常大的公司非常重要的项目) pro:正式环境 灰度环境与正式环境的服务器配置…

Azure 机器学习 - 使用受保护工作区时的网络流量流

目录 环境准备入站和出站要求方案&#xff1a;从工作室访问工作区方案&#xff1a;从工作室使用 AutoML、设计器、数据集和数据存储方案&#xff1a;使用计算实例和计算群集方案&#xff1a;使用联机终结点入站通信出站通信 方案&#xff1a;使用 Azure Kubernetes 服务方案&am…

数据结构线性表——栈

前言&#xff1a;哈喽小伙伴们&#xff0c;今天我们将一起进入数据结构线性表的第四篇章——栈的讲解&#xff0c;栈还是比较简单的哦&#xff0c;跟紧博主的思路&#xff0c;不要掉队哦。 目录 一.什么是栈 二.如何实现栈 三.栈的实现 栈的初始化 四.栈的操作 1.数据入栈…

Kafka中遇到的错误:

1、原因&#xff1a;kafka是一个去中心化结果的&#xff0c;所以在启动Kafka的时候&#xff0c;每一个节点上都需要启动。 启动的命令&#xff1a;kafka-server-start.sh -daemon /usr/local/soft/kafka_2.11-1.0.0/config/server.properties

力扣刷题-二叉树-二叉树的层序遍历(相关题目总结)

思路 层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。 需要借用一个辅助数据结构即队列来实现&#xff0c;队列先进先出&#xff0c;符合一层一层遍历的逻辑&#xff0c;而用栈先进后出适合模拟深度优先遍历也就是递归的…

【ruoyi】微服务关闭登录验证码

登录本地的nacos服务&#xff0c;修改&#xff1a;配置管理-配置列表-ruoyi-gateway-dev.yml 将验证码的enabled设置成false&#xff0c;即可

5+干湿结合的佳作,可另外添加分析升级

今天给同学们分享一篇生信文章“PCTAIRE Protein Kinase 1 (PCTK1) Suppresses Proliferation, Stemness,and Chemoresistance in Colorectal Cancer through the BMPR1B-Smad1/5/8 Signaling Pathway”&#xff0c;这篇文章发表在Int J Mol Sci期刊上&#xff0c;影响因子为5.…

计算机网络:概述

0 学时安排及讨论题目 0.1讨论题目&#xff1a; CSMA/CD协议交换机基本原理ARP协议及其安全子网划分IP分片路由选择算法网络地址转换NATTCP连接建立和释放再论网络体系结构 0.2 本节主要内容 计算机网络在信息时代中的作用 互联网概述 互联网的组成 计算机网络在我国的发展 …

2024 款:最新前端技术趋势

Hello&#xff0c;大家好&#xff0c;我是 Sunday。 上一次的时候聊了 那么些已经落后的前端开发技术 。但是光知道什么技术落后了是不够的&#xff0c;咱们还得知道 前端最新的技术趋势是什么。所以&#xff0c;今天这篇文章&#xff0c;咱们就来聊一聊&#xff0c;2023 最新…

Android T 实现简易的 USB Mode Select 需求

Android T 实现 USB Mode Select 需求 一、实现效果 二、主要实现思路 在手机连接 USB 发生/取消通知的同时&#xff0c;控制弹窗 Dialog 的显示/消失。 三、主要代码实现 连接 USB 发送/取消的主要实现是在 UsbDeviceManager.java 类中。类路径如下&#xff1a; system/f…

SAP实现文本框多行输入(类cl_gui_textedit)

参考文章&#xff1a;https://blog.csdn.net/SAPmatinal/article/details/130882962 先看效果&#xff0c;在输入框先来一段《赤壁赋》 然后点击 ‘保存输出’按钮&#xff0c;就能把输入内容从表里读取并输出来 源代码&#xff1a; *&-------------------------------…

【云备份项目总结】客户端篇

项目总结 整体回顾util.hppdata.hppcloud.hpp 代码 客户端的代码与服务端的代码实现有很多相似之处&#xff0c;我们也只编写一个简单的客户端代码。 整体回顾 客户端要实现的功能是&#xff1a;对指定文件夹中的文件自动进行备份上传。但是并不是所有的文件每次都需要上传&am…

css style、css color 转 UIColor

你能看过来&#xff0c;就说明这个问题很好玩&#xff01;IT开发是一个兴趣&#xff0c;更是一个挑战&#xff01;兴趣使你工作有热情。挑战使让你工作充满刺激拉满的状态&#xff01;我们日复一日年复一年的去撸代码&#xff0c;那些普普通通的功能代码&#xff0c;已经厌倦了…

AI 绘画 | Stable Diffusion 高清修复、细节优化

前言 在 Stable Diffusion 想要生成高清分辨率的图片。在文生图的功能里&#xff0c;需要设置更大的宽度和高度。在图生图的功能里&#xff0c;需要设置更大的重绘尺寸或者重绘尺寸。但是设置完更大的图像分辨率&#xff0c;需要更大显存&#xff0c;1024*1024的至少要电脑的空…

Python 框架学习 Django篇 (九) 产品发布、服务部署

我们前面编写的所有代码都是在windows上面运行的&#xff0c;因为我们还处于开发阶段 当我们完成具体任务开发后&#xff0c;就需要把我们开发的网站服务发布给真正的用户 通常来说我们会选择一台公有云服务器比如阿里云ecs&#xff0c;现在的web服务通常都是基于liunx操作系统…

11-13 周一 同济子豪兄CNN卷积神经网络学习记录

11-13 周一 同济子豪兄CNN卷积神经网络学习记录 时间版本修改人描述2023年11月13日14:02:14V0.1宋全恒新建文档2023年11月13日19:05:29V0.2宋全恒完成 大白话讲解卷积神经网络的学习 简介 为了深入理解CNN&#xff0c;进行B站 同济子豪兄深度学习之卷积神经网络的学习. 主要内…

Halcon WPF 开发学习笔记(3):WPF+Halcon初步开发

文章目录 前言在MainWindow.xaml里面导入Halcon命名空间WPF简单调用Halcon创建矩形简单调用导出脚本函数 正确显示匹配效果 前言 本章会简单讲解如何调用Halcon组件和接口&#xff0c;因为我们是进行混合开发模式。即核心脚本在平台调试&#xff0c;辅助脚本C#直接调用。 在M…

实验一 Anaconda安装和使用(Python程序设计实验报告)

实验一 Anaconda安装和使用 一、实验环境 Python集成开发环境IDLE/Anaconda 二、实验目的 1&#xff0e;掌握Windows下Anaconda的安装和配置。 2. 掌握Windows下Anaconda的简单使用&#xff0c;包括IDLE、Jupyter Notebook、Spyder工具的使用。 3. 掌握使用pip管理Python扩展库…