【数据结构】树与二叉树(八):二叉树的中序遍历(非递归算法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;
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Revit 平面的圆弧,空间的椭圆弧

大家对Revit的空间曲线那么理解,如何用代码创建空间的椭圆弧,,上看是圆弧,正面看是椭圆? 直接放代码: Document doc = commandData.Application.ActiveUIDocument.Document; Autodesk.Revit.DB.XYZ center = new Autodesk.Revit.DB.XYZ(0, 0, 0); …

更安全的ssh协议与Gui图形化界面使用

目录 前言&#xff1a; 一.Gui图形化界面的使用 二.ssh协议 SSH的主要作用包括&#xff1a; 相比其他网络协议&#xff0c;SSH的优势包括&#xff1a; 三.idea集成Git 前言&#xff1a; 上一篇讲解了git的命令用法以及https协议&#xff0c;但是这个协议放在做团队项目的…

Redis中的Zset类型

目录 Zset的相关命令 zadd zrange zcard zcount zrevrange zrangebyscore zpopmax bzpopmax zpopmin和bzpopmin zrank zrevrank zscore zrem zremrangebyrank zremrangebyscore 操作集合间的命令 zinterstore和zunionstore 内部编码 Zset的应用场景 Zset表…

【Linux系统化学习】冯诺依曼体系结构 | 操作系统

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 目录 冯诺依曼体系结构 组成介绍 CPU和内存 以使用微信发消息为例理解冯诺依曼体系结构 操作系统 冯诺依曼体系结构 随着世界上第一台计算机ENIAC&#xff08;埃尼阿克&#xff09;的…

多级缓存之缓存同步

缓存数据同步的常见方式有三种&#xff1a; 设置有效期&#xff1a;给缓存设置有效期&#xff0c;到期后自动删除。再次查询时更新 优势&#xff1a;简单、方便缺点&#xff1a;时效性差&#xff0c;缓存过期之前可能不一致场景&#xff1a;更新频率较低&#xff0c;时效性要…

粘性定位-最下面怎么出现留白

问题&#xff1a;出现了留白 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title…

Fiddler Everywhere for Mac:一款强大且实用的网络调试工具

Fiddler Everywhere是一款备受Mac用户喜爱的网络调试工具&#xff0c;它具有强大的功能和易用性。作为一款老牌抓包工具&#xff0c;Fiddler Everywhere在Mac平台上拥有广泛的应用场景&#xff0c;无论是Web开发、移动应用开发还是网络调试&#xff0c;它都能提供全面的解决方案…

Ubuntu 22.04源码安装cmake 3.27.7

安装参考博客是《ubuntu安装cmake》和《Ubuntu 安装CMake》。 https://cmake.org/download是cmake官网下载的网址。 sudo wget -c https://github.com/Kitware/CMake/releases/download/v3.27.7/cmake-3.27.7.tar.gz可以下载源码&#xff0c;最后显示‘cmake-3.27.7.tar.gz’…

ARM-Cortex_M3/M4处理器开发简介

一、关于ARM-Cortex_M4处理器 ARM-Cortex_M3和ARM-Cortex_M4处理器使用32位架构&#xff0c;寄存器组中的内部寄存器、数据通路以及总线接口都是32位的&#xff0c;两者均基于ARMv7-M架构。 1、 Cortex_M处理器使用的指令集架构&#xff08;ISA&#xff09;为Thumb ISA&…

lv11 嵌入式开发 ARM体系结构理论基础(寄存器)3

目录 1 寄存器 2 ARM寄存器 2.1 专用寄存器 1 寄存器 概念 寄存器是处理器内部的存储器&#xff0c;没有地址 作用 一般用于暂时存放参与运算的数据和运算结果 注&#xff1a;全局变量不应该存入寄存器&#xff0c;数量有限会占用寄存器资源&#xff0c;寄存器读…

算法秘籍-王一博 | 数据结构与算法

⭐简单说两句⭐ 作者&#xff1a;后端小知识 CSDN个人主页&#xff1a;后端小知识 &#x1f50e;GZH&#xff1a;后端小知识 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 数据结构和算法是计算机科学的基石&#xff0c;是计算机的灵魂&…

js将图片文件转为base64格式

/***图片文件转换成BASE64字符串&#xff0c;异步任务*param {File} file图片文件对象*return {String} BASE64字符串*/ const getBase64 (file: File) > new Promise((resolve: (url: string) > void, reject) > {const reader new FileReader();reader.onload ()…

C 语言 break和continue语句

C 语言 break和continue语句 我们在之前的教程中了解了循环。在本教程中&#xff0c;我们将在示例的帮助下学习使用break和继续语句。 C 语言 break break语句在遇到循环时将立即结束循环。其语法为&#xff1a; break;break语句几乎总是与if…else循环内的语句一起使用。 …

SpringBoot实现Excel导入导出

SpringBoot实现Excel导入导出 在我们平时工作中经常会遇到要操作Excel的功能&#xff0c;比如导出个用户信息或者订单信息的Excel报表。你肯定听说过 POI这个东西&#xff0c;可以实现。但是POI实现的API确实很麻烦&#xff0c;它需要写那种逐行解析的代码&#xff08;类似Xm…

MicroPython ESP32 RTC功能使用介绍

MicroPython ESP32 RTC功能使用介绍 &#x1f4cc;Micropython esp32官方文档介绍&#xff1a;https://docs.micropython.org/en/latest/esp32/quickref.html#real-time-clock-rtc&#x1f516;本示例基于Thonny平台开发。&#x1f33f;使用ESP32S3开发板测试。✨所使用的固件版…

2023双十一:实体门店闯入,第二战场全面开战

“闺女&#xff0c;吃饺子了吗&#xff1f;”11月8日&#xff0c;立冬&#xff0c;忙碌一天的陈曦回家路上接到母亲电话&#xff0c;才想起来家里冷冻水饺没了&#xff0c;又不想再去超市&#xff0c;直接打开美团买菜买了两袋&#xff0c;回家就煮了吃。当然&#xff0c;最终她…

多级缓存之实现多级缓存

多级缓存的实现离不开Nginx编程&#xff0c;而Nginx编程又离不开OpenResty。 1. OpenResty快速入门 我们希望达到的多级缓存架构如图&#xff1a; 其中&#xff1a; windows上的nginx用来做反向代理服务&#xff0c;将前端的查询商品的ajax请求代理到OpenResty集群 OpenRest…

最详细的LightGBM参数介绍与深入分析

前言 我使用LightGBM有一段时间了&#xff0c;它一直是我处理大多数表格数据问题的首选算法。它有很多强大的功能&#xff0c;如果你还没有看过的话&#xff0c;我建议你去了解一下。 但我一直对了解哪些参数对性能影响最大&#xff0c;以及如何调整LightGBM参数以发挥最大作用…

Python算法:动态规划解决0-1背包问题

动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;是一种在数学、计算机科学和经济学中使用的&#xff0c;通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题&#xff0c;它能够将问题…

Android修行手册 - POI操作Excel常用样式(字体,背景,颜色,Style)

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…