【数据结构】树与二叉树(八):二叉树的中序遍历(非递归算法NIO)

文章目录

5.2.1 二叉树

  二叉树是一种常见的树状数据结构,它由结点的有限集合组成。一个二叉树要么是空集,被称为空二叉树,要么由一个根结点和两棵不相交的子树组成,分别称为左子树右子树。每个结点最多有两个子结点,分别称为左子结点和右子结点。
在这里插入图片描述

二叉树性质

引理5.1:二叉树中层数为i的结点至多有 2 i 2^i 2i个,其中 i ≥ 0 i \geq 0 i0

引理5.2:高度为k的二叉树中至多有 2 k + 1 − 1 2^{k+1}-1 2k+11个结点,其中 k ≥ 0 k \geq 0 k0

引理5.3:设T是由n个结点构成的二叉树,其中叶结点个数为 n 0 n_0 n0,度数为2的结点个数为 n 2 n_2 n2,则有 n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1

  • 详细证明过程见前文:【数据结构】树与二叉树(三):二叉树的定义、特点、性质及相关证明

满二叉树、完全二叉树定义、特点及相关证明

  • 详细证明过程见前文:【数据结构】树与二叉树(四):满二叉树、完全二叉树及其性质

5.2.2 二叉树顺序存储

  二叉树的顺序存储是指将二叉树中所有结点按层次顺序存放在一块地址连续的存储空间中,详见:
【数据结构】树与二叉树(五):二叉树的顺序存储(初始化,插入结点,获取父节点、左右子节点等)

5.2.3 二叉树链接存储

  二叉树的链接存储系指二叉树诸结点被随机存放在内存空间中,结点之间的关系用指针说明。在链式存储中,每个二叉树结点都包含三个域:数据域(Data)、左指针域(Left)和右指针域(Right),用于存储结点的信息和指向子结点的指针,详见:
【数据结构】树与二叉树(六):二叉树的链式存储

5.2.4 二叉树的遍历

  • 遍历(Traversal)是对二叉树中所有节点按照一定顺序进行访问的过程。
  • 通过遍历,可以访问树中的每个节点,并按照特定的顺序对它们进行处理。
  • 对二叉树的一次完整遍历,可给出树中结点的一种线性排序。
    • 在二叉树中,常用的遍历方式有三种:先序遍历中序遍历后序遍历
    • 这三种遍历方式都可以递归地进行,它们的区别在于节点的访问顺序
      • 在实现遍历算法时,需要考虑递归终止条件和递归调用的顺序。
    • 还可以使用迭代的方式来实现遍历算法,使用栈或队列等数据结构来辅助实现。
  • 遍历是二叉树中基础而重要的操作,它为其他许多操作提供了基础,如搜索、插入、删除等。
    在这里插入图片描述

1-3 先序、中序、后序遍历递归实现及相关练习

【数据结构】树与二叉树(七):二叉树的遍历(先序、中序、后序及其C语言实现)

中序遍历递归实现

void inOrderTraversal(struct Node* root) {if (root == NULL) {return;}// 递归遍历左子树inOrderTraversal(root->left);// 访问根节点printf("%c ", root->data);// 递归遍历右子树inOrderTraversal(root->right);
}

4. 中序遍历非递归

a. 算法NIO

在这里插入图片描述

b. 算法解读

  NIO算法利用了一个辅助堆栈S来模拟递归过程中的函数调用栈。通过在循环中不断将左子节点入栈,然后处理栈顶节点,并将指针移动到右子节点,实现了中序遍历的非递归算法。

  1. 创建一个空堆栈S,并将指针p指向树的根节点t。
  2. 进入循环,只要p不为空,执行以下步骤:
    a. 将p入栈S。
    b. 将p指向其左子节点(p = Left( p ))。
  3. 如果堆栈S为空,则结束算法。
  4. 从堆栈S中弹出栈顶元素,并将p指向弹出的节点。
  5. 打印p节点的值。
  6. 将p指向p的右子节点(p = Right( p ))。
  7. 跳转到步骤2,继续循环。

  该算法的时间复杂度为O(n),其中n是二叉树中节点的数量。因为每个节点都会被访问一次且入栈一次,所以算法的时间复杂度与节点数量成正比。

  这个非递归中序遍历算法可以应用于需要遍历二叉树并按照中序顺序访问节点的场景,例如在构建二叉树的线索化结构时,或者需要按照中序顺序遍历二叉搜索树等情况下。

c. 典例剖析

在这里插入图片描述

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

d.代码实现

void nonRecursiveInOrder(struct Node* root) {struct Node* stack[100];  // 辅助堆栈,用于模拟递归调用栈int top = -1;  // 栈顶指针struct Node* current = root;while (current != NULL || top != -1) {// 将当前结点的左子结点入栈while (current != NULL) {stack[++top] = current;current = current->left;}// 弹出栈顶结点,并访问current = stack[top--];printf("%c ", current->data);// 处理右子结点current = current->right;}
}

5. 代码整合

#include <stdio.h>
#include <stdlib.h>// 二叉树结点的定义
struct Node {char data;struct Node* left;struct Node* right;
};// 创建新结点
struct Node* createNode(int data) {struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));if (newNode == NULL) {printf("Memory allocation failed!\n");exit(1);}newNode->data = data;newNode->left = NULL;newNode->right = NULL;return newNode;
}
// 递归中序遍历
void inOrderTraversal(struct Node* root) {if (root == NULL) {return;}// 递归遍历左子树inOrderTraversal(root->left);// 访问根节点printf("%c ", root->data);// 递归遍历右子树inOrderTraversal(root->right);
}// 非递归中序遍历
void nonRecursiveInOrder(struct Node* root) {struct Node* stack[100];  // 辅助堆栈,用于模拟递归调用栈int top = -1;  // 栈顶指针struct Node* current = root;while (current != NULL || top != -1) {// 将当前结点的左子结点入栈while (current != NULL) {stack[++top] = current;current = current->left;}// 弹出栈顶结点,并访问current = stack[top--];printf("%c ", current->data);// 处理右子结点current = current->right;}
}int main() {// 创建一棵二叉树struct Node* root = createNode('a');root->left = createNode('b');root->right = createNode('c');root->left->left = createNode('d');root->left->right = createNode('e');root->left->right->left = createNode('f');root->left->right->right = createNode('g');// 递归中序遍历二叉树printf("Recursive In-order traversal: \n");inOrderTraversal(root);printf("\n");// 非递归中序遍历二叉树printf("Non-recursive In-order traversal:\n");nonRecursiveInOrder(root);printf("\n");return 0;
}

在这里插入图片描述

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

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

相关文章

20.1 platform 设备驱动

一、Linux 驱动的分离与分层 1. 驱动的分隔和分离 现在有三个平台&#xff0c;A、B 和 C&#xff0c;这三个平台都有 MPU6050 设备。编写最简单的驱动框架如下图&#xff1a; 每个平台下都有一个主机驱动和设备驱动&#xff0c;主机驱动是必要的&#xff0c;因为不同的平台 I2…

服务器数据恢复—磁盘出现坏道掉线导致raid5阵列崩溃的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌服务器中有一组16块SAS接口硬盘组建的raid5磁盘阵列。 服务器故障&检测&#xff1a; 服务器raid5阵列中有2块硬盘掉线&#xff0c;上层服务器应用崩溃&#xff0c;导致服务器数据丢失。丢失的数据主要是4个1.5TB大小的卷中的数据&am…

Mysql-表的结构操作

1.创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎 ; 说明&#xff1a; field 表示列名 datatype 表示列的类型 character set 字符集&#xff0c;如果没有指定字…

【中间件篇-Redis缓存数据库08】Redis设计、实现、redisobject对象设计、多线程、缓存淘汰算法

Redis的设计、实现 数据结构和内部编码 type命令实际返回的就是当前键的数据结构类型&#xff0c;它们分别是&#xff1a;string(字符串)hash(哈希)、list(列表)、set(集合)、zset (有序集合)&#xff0c;但这些只是Redis对外的数据结构。 实际上每种数据结构都有自己底层的…

CAD Exchanger SDK 须知的开发配置--Crack

支持的配置 目录 支持的编程语言 C 支持C# 支持Java支持Python支持JavaScript 支持 CAD Exchanger SDK 是一组跨平台库&#xff0c;目前支持下列配置。随着时间的推移&#xff0c;旧版本的编译器、体系结构或依赖的第三方库从主要支持级别变为次要支持级别&#xff0c;然后被弃…

将 ONLYOFFICE 文档编辑器与 С# 群件平台集成

在本文中&#xff0c;我们会向您展示 ONLYOFFICE 文档编辑器与其自有的协作平台集成。 ONLYOFFICE 是一款开源办公套件&#xff0c;包括文本文档、电子表格和演示文稿编辑器。这款套件支持用户通过文档编辑组件扩展第三方 web 应用的功能&#xff0c;可直接在应用的界面中使用。…

C# Onnx LSTR 基于Transformer的端到端实时车道线检测

目录 效果 模型信息 项目 代码 下载 效果 模型信息 lstr_360x640.onnx Inputs ------------------------- name&#xff1a;input_rgb tensor&#xff1a;Float[1, 3, 360, 640] name&#xff1a;input_mask tensor&#xff1a;Float[1, 1, 360, 640] -----------------…

开发vue3 UI组件库,并且发布到NPM

目录 1.创建vue3工程 2.创建package文件 3.编写组件&#xff0c;并且导出 4.编写package.json 5.npm账号注册登录并发布 6.从npm安装使用 7.注意事项 1.创建vue3工程 &#xff08;1&#xff09;初始化Vue项目 cnpm create vite &#xff08;2&#xff09;进入文件夹…

计算机基础知识50

数据的增删改查(insert update delete select) # 用户列表的展示&#xff1a; # 把数据表中得用户数据都给查询出来展示在页面上 1. 查询 from app01 import models models.UserInfo.objects.all() # 查询所有的字段信息和数据 resmodels.UserInfo.objects.first() # 查询…

sass 生成辅助色

背景 一个按钮往往有 4 个状态。 默认状态hover鼠标按下禁用状态 为了表示这 4 个状态&#xff0c;需要设置 4 个颜色来提示用户。 按钮类型一般有 5 个&#xff1a; 以 primary 类型按钮为例&#xff0c;设置它不同状态下的颜色&#xff1a; <button class"btn…

ros2_control的简单应用

文章目录 简介插件实现函数介绍代码 调用原理局限性 简介 在利用moveit_setup_assistant配置我们自己机械手后&#xff0c;当运行demo.launch.py时&#xff0c;会实例化一个moveit对象以及一个基于ros2_control的、虚拟的控制对象&#xff0c;从而可以实现一个完整的控制闭环。…

Rust 中的引用与借用

目录 1、引用与借用 1.1 可变引用 1.2 悬垂引用 1.3 引用的规则 2、slice 类型 2.1 字符串字面量其实就是一个slice 2.2 总结 1、引用与借用 在之前我们将String 类型的值返回给调用函数&#xff0c;这样会导致这个String会被移动到函数中&#xff0c;这样在原来的作用域…