创作

完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>

3天内不再提示

4中二叉树的遍历方式介绍

lviY_AI_shequ 来源:未知 作者:胡薇 2018-04-27 17:23 次阅读

对于一种数据结构而言,遍历是常见操作。二叉树是一种基本的数据结构,是一种每个节点的儿子数目都不多于2的树。二叉树的节点声明如下:

typedef struct TreeNode *PtrToNode;

typedef struct TreeNode *BinTree;

struct TreeNode

{

int Data; //为简单起见,不妨假设树节点的元素为int型

BinTree Left;

BinTree Right;

};

二叉树的遍历主要有先序遍历,中序遍历,后序遍历,层序遍历四种方式,下面一一介绍。

1. 先序遍历

在先序遍历中,对节点的访问工作是在它的左右儿子被访问之前进行的。换言之,先序遍历访问节点的顺序是根节点-左儿子-右儿子。由于树可以通过递归来定义,所以树的常见操作用递归实现常常是方便清晰的。递归实现的代码如下:

void PreOrderTraversal(BinTree BT)

{

if( BT )

{

printf(“%d\n”, BT->Data); //对节点做些访问比如打印

PreOrderTraversal(BT->Left); //访问左儿子

PreOrderTraversal(BT->Right); //访问右儿子

}

}

由递归代码可以看出,该递归为尾递归(尾递归即递归形式在函数末尾或者说在函数即将返回前)。尾递归的递归调用需要用栈存储调用的信息,当数据规模较大时容易越出栈空间。虽然现在大部分的编译器能够自动去除尾递归,但是即使如此,我们不妨自己去除。非递归先序遍历算法基本思路:使用堆栈

a. 遇到一个节点,访问它,然后把它压栈,并去遍历它的左子树;

b. 当左子树遍历结束后,从栈顶弹出该节点并将其指向右儿子,继续a步骤;

c. 当所有节点访问完即最后访问的树节点为空且栈空时,停止。

实现代码如下:

void PreOrderTraversal(BinTree BT)

{

BinTree T = BT;

Stack S = CreatStack(MAX_SIZE); //创建并初始化堆栈S

while(T || !IsEmpty(S))

{

while(T) //一直向左并将沿途节点访问(打印)后压入堆栈

{

printf("%d\n", T->Data);

Push(S, T);

T = T->Left;

}

if (!IsEmpty(S))

{

T = Pop(S); //节点弹出堆栈

T = T->Right; //转向右子树

}

}

}

2. 中序遍历

中序遍历的遍历路径与先序遍历完全一样。其实现的思路也与先序遍历非常相似。其主要的不同点是访问节点顺序不同:中序遍历是访问完所有左儿子后再访问根节点,最后访问右儿子,即为左儿子-根节点-右儿子。

递归实现的代码如下:

void InOrderTraversal(BinTree BT)

{

if(BT)

{

InOrderTraversal(BT->Left);

printf("%d\n", BT->Data);

InOrderTraversal(BT->Right);

}

}

非递归辅助栈实现代码如下:

void InOrderTraversal(BinTree BT)

{

BinTree T = BT;

Stack S = CreatStack(MaxSize); //创建并初始化堆栈S

while(T || !IsEmpty(S))

{

while(T) //一直向左并将沿途节点压入堆栈

{

Push(S,T);

T = T->Left;

}

if(!IsEmpty(S))

{

T = Pop(S); //节点弹出堆栈

printf("%d\n", T->Data); //(访问) 打印结点

T = T->Right; //转向右子树

}

}

}

非递归不用辅助栈实现中序遍历:

试设计一个非递归算法,按中根顺序遍历非线索二叉树,但不得用任何辅助栈。在执行算法期间,允许改变左孩子指针和右孩子指针的值。

算法:右线索化+回溯

若当前树的根节点p有左孩子且未被线索化:将其左孩子的最右结点(可为左孩子本身)指向p,即右线索化,然后p = p->lChild;

若p有左孩子但已被线索化,说明该p是回溯上来的,即左孩子已经被访问了,则释放线索化的指针;

若p无左孩子,打印p,向上回溯(即p = p->rChild)。

代码如下:

/*

输入:ABDH##I##E##CF#J##G##

*/

#include

typedef struct BTNode* Position;

typedef Position BTree;

typedef char ElementType;

struct BTNode {

ElementType data;

Position lChild, rChild;

};

BTree CreateBTree(void);

void Inorder(BTree bt);

int main()

{

BTree bt = CreateBTree();

Inorder(bt);

return 0;

}

void Inorder(BTree bt)

{

Position p = bt;

while (p)

{

Position pLeft = p->lChild;

if (pLeft)

{

while (pLeft->rChild && pLeft->rChild != p) //找到以p为根结点的树的最右孩子

pLeft = pLeft->rChild;

if (pLeft->rChild == NULL) //线索化

{

pLeft->rChild = p;

p = p->lChild;

continue;

}

else //线索化后已被访问

{

pLeft->rChild = NULL; //释放指向根节点(祖先)的指针

}

}

printf("%c ", p->data); //打印

p = p->rChild; //向上回溯或者转向右子树

}

printf("\n");

}

BTree CreateBTree() //按照先序序列建立二叉树

{

BTree bt = NULL;

char ch;

scanf("%c", &ch);

if (ch != '#') //'#'代表空节点

{

bt = new BTNode;

bt->data = ch;

bt->lChild = CreateBTree();

bt->rChild = CreateBTree();

}

return bt;

}

运行结果:

参考博客:http://m.blog.csdn.net/blog/Raito__/40618257

3. 后序遍历

后序遍历与中序遍历,先序遍历的路径也完全一样。主要的不同点是后序遍历访问节点的顺序是先访问左儿子和右儿子,最后访问节点,即左儿子-右儿子-根节点。

递归实现思路与中序遍历和先序遍历相似,代码如下:

void PostOrderTraversal(BinTree BT)

{

if (BT)

{

PostOrderTraversal(BT->Left);

PostOrderTraversal(BT->Right);

printf("%d\n", BT->Data);

}

}

后序遍历的非递归实现

思路一:

对于一个节点而言,要实现访问顺序为左儿子-右儿子-根节点,可以利用后进先出的栈,在节点不为空的前提下,依次将根节点,右儿子,左儿子压栈。故我们需要按照根节点-右儿子-左儿子的顺序遍历树,而我们已经知道先序遍历的顺序是根节点-左儿子-右儿子,故只需将先序遍历的左右调换并把访问方式打印改为压入另一个栈即可。最后一起打印栈中的元素。代码如下:

void PostOrderTraversal(BinTree BT)

{

BinTree T = BT;

Stack S1 = CreatStack(MAX_SIZE); //创建并初始化堆栈S1

Stack S2 = CreatStack(MAX_SIZE); //创建并初始化堆栈S2

while(T || !IsEmpty(S1))

{

while(T) //一直向右并将沿途节点访问(压入S2)后压入堆栈S1

{

Push(S2, T);

Push(S1, T);

T = T->Right;

}

if (!IsEmpty(S1))

{

T = Pop(S1); //节点弹出堆栈

T = T->Left; //转向左子树

}

}

while(!IsEmpty(S2)) //访问(打印)S2中元素

{

T = Pop(S2);

printf("%d\n", T->Data);

}

}

思路一的优点是由于利用了先序遍历的思想,代码较简洁,思路较清晰。缺点是需要用一个栈来存储树的所有节点,空间占用较大。

思路二:

要访问一个节点的条件上一个访问的节点是右儿子。我们可以增加一个变量Prev来判断当前节点Curr的上一个节点与它的关系来执行相应的操作。

若Prev为空(Curr节点是根节点)或者Prev是Curr的父节点,将Curr节点的左孩子和右孩子分别压入栈;

若Prev是Curr的左儿子,则将Curr的右儿子压入栈;

否则Prev是Curr的右儿子,访问Curr;

代码如下:

void PostOrderTraversal(BinTree BT)

{

if(BT == NULL)

return ;

Stack S = CreatStack(MAX_SIZE);

BinTree Prev = NULL , Curr = NULL; //初始化

s.push(BT);

while(!IsEmpty(S))

{

Curr = Top(S); //将栈顶元素赋给Curr

if(Prev == NULL || Prev->Left == Curr || Prev->Right == Curr) //若Prev为NULL或是Curr的父节点

{

if(Curr->Left != NULL)

Push(S, Curr->Left);

else if(Curr->Right != NULL)

Push(S, Curr->Right);

}

else if(Curr->Left == Prev) //若Prev是Curr的左儿子

{

if(Curr->Right != NULL)

Push(S, Curr->Right);

}

else

{

printf("%d\n", Curr->Data); //访问当前节点

Pop(S); //访问后弹出

}

Prev = Curr; //处理完当前节点后将Curr节点变为Prev节点

}

}

4. 层序遍历

二叉树遍历的核心问题是二维结构的线性化。我们通过节点访问其左右儿子时,存在的问题是访问左儿子后,右儿子怎么访问。因此我们需要一个存储结构保存暂时不访问的节点。前面三种遍历方式的非递归实现,我们是通过堆栈来保存。事实上也可以通过队列来保存。

队列实现的基本思路:遍历从根节点开始,首先将根节点入队,然后执行循环:节点出队,访问(访问)根节点,将左儿子入队,将右儿子入队,直到队列为空停止。

这种遍历方式的结果是将二叉树从上到下,从左至右一层一层的遍历,即层序遍历,代码实现如下:

void LevelOrderTraversal(BinTree BT)

{

BinTree T;

Queue Q; //声明一个队列

if (BT == NULL)

return; //如果树为空,直接返回

Q = CreatQueue(MAX_SIZE); //创建并初始化队列

AddQ(Q, BT); //将根节点入队

while (!IsEmpty(Q))

{

T = DeleteQ(Q); //节点出队

printf("%d\n", T->Data); //访问出队的节点

if (T->Left) AddQ(Q, T->Left); //若左儿子不为空,将其入队

if (T->Right) AddQ(Q, T->Right) //若右儿子不为空,将其入队

}

}

  • 节点
    +关注

    关注

    0

    文章

    143

    浏览量

    22493
  • 二叉树
    +关注

    关注

    0

    文章

    43

    浏览量

    11078
收藏 人收藏

    评论

    相关推荐

    LoRa节点、LoRa服务器和终端应用之间的数据传输

    通过本 LAT 实现一个从 LoRa 节点、LoRa 服务器、终端应用之间的数据或者命令的相互传输的....
    的头像 STM32单片机 发表于 06-16 16:43 433次 阅读

    Bitcoin XT Bitcoin​分支

    bitcoinxt.zip
    发表于 06-06 15:21 22次 阅读
    Bitcoin XT Bitcoin​分支

    Toshi比特币节点

    toshi.zip
    发表于 06-06 15:13 18次 阅读
    Toshi比特币节点

    双向循环链表的创建

    需要注意的是,虽然双向循环链表成环状,但本质上还是双向链表,因此在双向循环链表中,依然能够找到头指针....
    的头像 C语言编程学习基地 发表于 05-24 16:27 388次 阅读

    DOM Treemap查看DOM节点的扩展

    ./oschina_soft/dom-treemap-devtools-extension.zip
    发表于 05-17 09:32 16次 阅读
    DOM Treemap查看DOM节点的扩展

    二叉树的最小深度

    遍历顺序上依然是后序遍历(因为要比较递归返回之后的结果),但在处理中间节点的逻辑上,最大深度很容易理....
    的头像 算法与数据结构 发表于 04-28 16:27 474次 阅读

    Caelus全场景在离线混部系统

    Caelus.zip
    发表于 04-28 10:34 35次 阅读
    Caelus全场景在离线混部系统

    蓝牙Mesh网络基础知识汇总

    在本文中,我们将熟悉一些基本的蓝牙网格概念,例如节点和元素。我们还将看到蓝牙网状网络中的节点有不同的....
    的头像 科技观察员 发表于 04-25 15:56 1141次 阅读
    蓝牙Mesh网络基础知识汇总

    现代电力系统分析作业(一)

    1、选用一种计算软件,计算 IEEE30 母线标准试验系统的潮流。并在此 基础上,计算观察: 1)....
    发表于 04-25 15:55 76次 阅读

    C语言数据结构:什么是二叉树?

    完全二叉树:完全二叉树是效率很高的数据结构。对于深度为K,有n个节点的二叉树,当且仅当每一个节点都与....
    的头像 C语言编程学习基地 发表于 04-21 16:20 469次 阅读

    openwrt节点包插件

    openwrt-node-packages.zip
    发表于 04-20 09:18 298次 阅读
    openwrt节点包插件

    《玩转ART-Pi开发板》第7章 基于ART-Pi的环境监测系统设计

    开发环境: RT-Thread版本:4.0.3 操作系统:Windows10 Keil版本:V5.30 RT-Thread Studio版本:2.0.1 开发板MC...
    发表于 04-18 14:49 955次 阅读

    Linux中的索引节点、软链接、硬链接是什么?

     回到计算机中,文件的所有信息都需要存储在硬盘上,因此就要对硬盘进行区域划分:不同的区域存储不同类型....
    的头像 十亿少男的梦 发表于 04-11 15:34 3226次 阅读
    Linux中的索引节点、软链接、硬链接是什么?

    RT-Thread之等待队列的定义及使用方法简析

    1. 等待队列是什么 等待队列是一个轻量级的线程间异步通讯方式。 他有两个特点: 轻量: API 较少异步: 2. 等待队列怎么使...
    发表于 04-11 10:40 1452次 阅读

    RK3399中PWM3如果用成普通的PWM功能改如何修改呢

    在Firefly 中RK3399系列,我们选择AIO-3399C(AI) 机器,有一路PWM3是用做红外遥控的功能,但是如果用成普通的PWM...
    发表于 04-08 16:49 5319次 阅读

    评估一下RV1126(RV1109)的AI性能

    一、推理图优化 下载下来的graph我采用netron进行了可视化,发现该graph中包含预处理op(tf中采用了element-wise op进行了组合,...
    发表于 04-06 16:34 2153次 阅读

    ARM系列之CHI协议介绍(一)

    1、ACE和CHI具体有什么不一样吗 CHI 的全称是 Coherent Hub Interface。所以从名字就能看出,CHI 要解决什么问题...
    发表于 04-02 14:41 4843次 阅读

    工程电路分析-第6版教材

    -工程电路分析-第6版教材免费下载。
    发表于 03-30 14:49 123次 阅读

    基于OpenHarmony的Adapter使用系列资料汇总

    说明 1、BaseQuickAdapter<T, VH>为最基本的类型,提供最基础的功能,所有子类都继承于此。 2、T 为数据类型;...
    发表于 03-23 16:35 1642次 阅读

    python解析库的使用--PyQuery

    PyQuery库也是一个非常强大又灵活的网页解析库,如果你有前端开发经验的,都应该接触过jQuery....
    的头像 python爬虫知识分享 发表于 03-22 16:07 1169次 阅读

    如何使用 go 实现红黑树

    二叉查找树也叫二叉搜索树,也叫二叉排序树,它具有以下特点:1. 如果左子树不为空,则左子树上的结点的....
    的头像 Linux爱好者 发表于 03-21 11:54 392次 阅读

    Merlin HugeCTR V3.4.1版本新增内容介绍

    Merlin HugeCTR(以下简称 HugeCTR)是 GPU 加速的推荐程序框架,旨在在多个 ....
    的头像 NVIDIA英伟达企业解决方案 发表于 03-10 10:15 388次 阅读

    如何在设备树文件里面添加心跳灯节点呢

    如何在设备树文件里面添加心跳灯节点呢?有哪些步骤? ...
    发表于 03-04 06:44 529次 阅读

    在rk3288 android5.1上如何去实现一个USB固定一个ttyUSB节点呢

    在rk3288 android5.1上如何去实现一个USB固定一个ttyUSB节点呢?其实现思路是怎样的?...
    发表于 03-03 07:18 568次 阅读

    怎样去判断RK3568固态硬盘上的PCIE节点是否生成呢

    怎样去判断RK3568固态硬盘上的PCIE节点是否生成呢?...
    发表于 03-02 07:11 585次 阅读

    Murata金属UHF RAIN RFID标签的详细介绍

    本期Digi-Key Daily向大家推介两款产品——Murata金属UHF RAIN RFID标签....
    的头像 得捷电子DigiKey 发表于 02-26 12:41 628次 阅读

    怎样去设计一种基于单片机的汽车车门节点控制器呢

    基于单片机的汽车车门节点控制器有何功能? 怎样去设计一种基于单片机的汽车车门节点控制器呢?...
    发表于 02-23 06:26 443次 阅读

    怎么去判断支路的个数呢

    支路是什么意思呢?怎么去判断支路的个数呢?
    的头像 工程师邓生 发表于 02-02 09:05 3363次 阅读

    二叉树上应该怎么求

      二叉树上应该怎么求,二叉搜索树上又应该怎么求? 在求众数集合的时候有一个技巧,因为题目中众数是可....
    的头像 算法与数据结构 发表于 11-22 11:32 589次 阅读

    数据结构与算法分析中的二叉树与堆有关知识汇总

    该资料包括数据结构与算法分析中的二叉树与堆有关的一些知识
    发表于 11-03 09:37 139次 阅读

    二叉排序树AVL如何实现动态平衡

      什么是AVL树 大家好,我是bigsai,好久不见,甚是想念,今天给大家讲讲AVL树。 对于树这....
    的头像 算法与数据结构 发表于 10-28 17:02 642次 阅读
    二叉排序树AVL如何实现动态平衡

    算法学习中如何打印二叉树节点

    大家好,我是吴师兄,直接开始今天的算法学习,冲冲冲。 一、题目描述 从上到下打印出二叉树的每个节点,....
    的头像 算法与数据结构 发表于 10-22 09:37 687次 阅读

    deepwalk算法核心的步骤

    在数据量越来越大的今天, word2vec是通过字词的共现关系来学习字词的向量表示,Graph Em....
    的头像 智能生物识别说 发表于 10-14 09:59 802次 阅读
    deepwalk算法核心的步骤

    如何修剪二叉搜索树

      如果不对递归有深刻的理解,本题有点难。单纯移除一个节点那还不够,要修剪! 669. 修剪二叉搜索....
    的头像 算法与数据结构 发表于 10-11 14:16 620次 阅读

    C++基础语法中的二叉树详解

    本期是C++基础语法分享的第十四节,今天给大家来梳理一下树!   二叉树 BinaryTree.cp....
    的头像 C语言编程学习基地 发表于 09-29 18:02 1109次 阅读

    如何才能够翻转二叉树

    这道题目是非常经典的题目,也是比较简单的题目(至少一看就会)。 但正是因为这道题太简单,一看就会,一....
    的头像 新材料在线 发表于 09-01 11:45 926次 阅读

    如何将网关连接到TTN服务器

    当需要连接网关到TTN的时候我们突然发现:在TTN V2版本上已经无法创建新的网关了。另外,V2版本....
    发表于 08-23 15:49 607次 阅读

    C语言编程中如何求出二叉树后序遍历

    题目 已知二叉树前序为 ABDFGCEH 后序序列为 BFDGACEH ,要求输出后序遍历为 FGD....
    的头像 C语言编程基础 发表于 08-23 11:04 2852次 阅读

    二叉树的所有路径介绍

    以为只用了递归,其实还用了回溯 257. 二叉树的所有路径 题目地址:https://leetcod....
    的头像 新材料在线 发表于 08-13 17:51 1495次 阅读
    二叉树的所有路径介绍

    如何TransCAD软件导入常用交通规划软件的网络数据?

    交通网络是有向图,例如道路网,大多数路段双向成对出现,也有部分单向交通组织的路段(单行道、高快速路单....
    的头像 TransCAD和TransModeler交通软件 发表于 07-04 16:43 2829次 阅读

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

    我们之前说了二叉树基础及二叉的几种遍历方式及练习题,今天我们来看一下二叉树的前序遍历非递归实现。 前....
    的头像 算法与数据结构 发表于 05-28 13:59 752次 阅读

    无线传感器网络节点定位算法研究与实现

    无线传感器网络节点定位算法研究与实现。
    发表于 05-24 09:34 303次 阅读

    采用PIC18F1320实现LIN从节点

    本应用笔记介绍如何使用增强型 USART(EAUSART)模块来实现基于 PIC18F1320 的 ....
    发表于 05-10 10:16 304次 阅读

    图的逻辑结构是怎样的?如何去实现它?

    其实在学习数据结构和算法的框架思维中说过,虽然图可以玩出更多的算法,解决更复杂的问题,但本质上图可以....
    的头像 算法与数据结构 发表于 05-08 16:34 2150次 阅读
    图的逻辑结构是怎样的?如何去实现它?

    以太网络的基础知识

    以太网络(Ethernet)为局域网络(Local area network, 简称LAN)中最常使....
    的头像 我快闭嘴 发表于 05-02 11:51 1389次 阅读
    以太网络的基础知识

    节点特征分析NSA技术培训教材资源下载

    电子产品的故障排除是个复杂的问题,往往是让人头疼。大批量的生产过程可以使用昂贵的大型自动化在线测试设....
    发表于 04-24 09:45 127次 阅读
    节点特征分析NSA技术培训教材资源下载

    CAN总线在COD检测中的应用

    CAN总线在COD检测中的应用说明。
    发表于 04-19 17:17 297次 阅读

    CAN总线节点软件的设计与实现

    CAN总线节点软件的设计与实现说明。
    发表于 04-19 16:59 332次 阅读

    LoRaWAN节点工作方式ClassB介绍

    Class B中的B的就是Beacon的意思,Class B的节点除了在rx1和rx2接收NS的数据....
    发表于 04-17 09:43 775次 阅读

    浅谈LoRaWAN节点工作方式ClassA和ClassC

    在这篇文章中,将为和大家分享节点的三种工作方式中的ClassA和ClassC。此文来自微信公众号“小....
    发表于 04-17 09:39 1756次 阅读
    浅谈LoRaWAN节点工作方式ClassA和ClassC

    LabVIEW的属性节点教学

    本文档的主要内容详细介绍的是LabVIEW初级教程之属性节点初级课程的详细资料说明。
    发表于 03-29 15:24 491次 阅读
    LabVIEW的属性节点教学

    面试官考点之索引是什么?

    可以从几个维度去看这个问题,查询是否够快,效率是否稳定,存储数据多少,以及查找磁盘次数等等。为什么不....
    的头像 数据分析与开发 发表于 03-05 10:37 1119次 阅读
    面试官考点之索引是什么?

    详解CANOPEN总线:最大长度和节点最多个数

    CANopen是一个基于CAN(控制局域网)串行总线系统和CAL(CAN应用层)的高层协议。CANo....
    的头像 工程师邓生 发表于 02-10 10:33 11800次 阅读
    详解CANOPEN总线:最大长度和节点最多个数

    构建图模型的关键步骤

    实体指的是具有可区别性且独立存在的某种事物,如某一个人、某一个城市、某一种植物、某一种商品等,是图模....
    的头像 h1654155199.4397 发表于 01-17 11:57 1264次 阅读
    构建图模型的关键步骤

    建立决策树的逻辑

    像上面的这样的二叉树状决策在我们生活中很常见,而这样的选择方法就是决策树。机器学习的方法就是通过平时....
    的头像 深度学习自然语言处理 发表于 10-10 10:44 1548次 阅读
    建立决策树的逻辑

    Max Howell因为不会翻转一棵二叉树,被Google拒绝

    Max Howell 就是 Homebrew 的创作者,也是一名业内知名的 MacOS / iOS ....
    的头像 算法与数据结构 发表于 09-03 10:52 9890次 阅读

    KUKA-WorkVisual-导出/导入PROFINET节点配置

    如果项目中已经有一个 PROFINET 配置,则该配置在导入时被覆盖,并且所有逻辑映射全部被删除!不....
    的头像 机器人及PLC自动化应用 发表于 08-07 16:07 5102次 阅读
    KUKA-WorkVisual-导出/导入PROFINET节点配置

    Offer系列面试题0:重建二叉树

    以本题的序列为例,前序遍历序列的第一个数字 3 就是根结点的值,在中序遍历序列,找到根结点值的位置。....
    的头像 算法与数据结构 发表于 07-09 15:03 932次 阅读
    Offer系列面试题0:重建二叉树

    红黑树(Red Black Tree)是一种自平衡的二叉搜索树

    平衡(Balance):就是当结点数量固定时,左右子树的高度越接近,这棵二叉树越平衡(高度越低)。而....
    的头像 算法与数据结构 发表于 07-01 15:05 1719次 阅读
    红黑树(Red Black Tree)是一种自平衡的二叉搜索树