数据结构与算法之树的遍历

简介: 树的 “前” “中” “后” 遍历//如果要再写一个树太费时间了,所以博主在这篇博客只给出核心代码并赋予GIF演示动画,望大家好好理解以对树的三种遍历方式有更为深刻的理解

树的 “前” “中” “后” 遍历

//如果要再写一个树太费时间了,所以博主在这篇博客只给出核心代码并赋予GIF演示动画,望大家好好理解以对树的三种遍历方式有更为深刻的理解

  因为递归调用函数是有开销的,而且递归的次数受堆栈大小的限制,所以本篇博客不会
介绍用递归的方式来遍历树.  而是使用 栈 来遍历树.
首先让我们来了解什么是栈?

栈是存放数据对象的一种特殊容器,栈中的元素始终遵循后进先出的顺序


前序遍历(博主上篇已经写过了,所以直接套用上篇的代码):

前序遍历的主要思想就是:

根节点最先入栈,最先出栈

右子节点先入栈后处理;

左子节点后入栈先处理.

  Btree tmp;
  SqStack stack;
  InitStack(stack);
  PushStack(stack, *root);  //根节点进栈
  while (!(IsEmpty(stack))) { //栈为空,所有节点均已处理 
    PopStack(stack, tmp);   //要遍历的节点  
    printf("- %d -", tmp.data);   //打印要便利的节点的值
    if (tmp.rchild != NULL) {
      PushStack(stack, *(tmp.rchild)); //右子节点先入栈,后处理  
    }
    if (tmp.lchild != NULL) {
      PushStack(stack, *(tmp.lchild)); //左子节点后入栈,接下来先 处理  
    }
  }

前序遍历演示

image.gif

void inOrder(BinTree *root)  //非递归中序遍历
{
     stack<BinTree*> s;
     BinTree *p=root;
     while(p!=NULL||!s.empty())
     {
         while(p!=NULL)
         {
             s.push(p);
             p=p->lchild;
         }
         if(!s.empty())
         {
             p=s.top();
             cout<<p->data<<"";
             s.pop();
             p=p->rchild;
         }
     }   
}

一开始我们 BinTree *p=root;这样就能执行我们的第一个while循环

当跳出第一个while()循环时,就代表我们的中序遍历已经结束了。


1.第二个while在p不为空时执行: 在while循环下,将根节点先入栈,左子节点后入栈,然后继续判断p是否为空再决定是否继续如果满足那么左子节点再继续入栈(因为根节点在最前面所以现在入栈的就只有左子节点了,不会存在根节点反复入栈的情况)。那么while循环完的时候,我们的节点p此时一定为NULL; 如果现在出栈的话我们一定能保证出战的元素使我们要出的第一个节点!!!


2.出栈以及后续操作 if 语句 : 在步骤1操作之后,根节点以及最左边的节点将会全部入栈。此时我们现在的p为NULL;这样我们是无法进行后续操作的,那么我们应该如何做呢???

其实很简单只需要让我们的 p 只想现在的栈顶元素,再将数据输出到控制台,再将这个元素在栈中出栈即可。因为左子节点以及用过了,所以现在我们就执行 p=p->rchile 那么此时又会存在两种情况

(1)存在右子节点------->即p不为空,那么又会进入到步骤1;知道变成第二种情况。

(2)不存在右子节点--------> 那么在执行操作2(即继续出栈,向上查找)


gif演示:

20191016222949963.gif


后序遍历:

void postOrder3(BinTree *root)     //非递归后序遍历
{
     stack<BinTree*> s;
     BinTree *cur;                      //当前结点
     BinTree *pre=NULL;                 //前一次访问的结点
     s.push(root);
     while(!s.empty())
     {
         cur=s.top();
         if((cur->lchild==NULL&&cur->rchild==NULL)||
           (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
         {
             cout<<cur->data<<"";  //如果当前结点没有孩子结点或者孩子节点都已被访问过
             s.pop();
             pre=cur;
         }
         else
         {
             if(cur->rchild!=NULL)
                 s.push(cur->rchild);
             if(cur->lchild!=NULL)   
                 s.push(cur->lchild);
         }
     }   
} 


对于后序遍历的理解:

首先定义两个可以指向树的指针

cur :指向当前节点

pre 指向上一个节点


现将根节点入栈(这一个会实现根节点最后出栈)


如果打while都已经跳出来了的话那么就说明已经完成后序遍历(因为我们先把根节点压进了栈,所以第一次是不会跳出我们的大循环的)


cur=s.top();将cur指向我们的栈顶(随着栈顶元素不断出栈,cur的指向会不断更改)


if(…) //如果当前结点没有孩子结点或者孩子节点都已被访问过(第一次循环的时候是不会进入这条语句的所以不要纠结最 孩子节点都已被访问过这句话!!!)

cout 想控制台打印元素,然后出栈

pre =cur; 这样就能实现pre指向上一个结点的功能了(也许会有人问,现在不是 pre=cur他们应该是指向一个结点的啊!!! 为什么要说 cur是指向当前节点 pre 是指向上一个结点啊? 因为在if结束了之后 cur就会指向新的栈顶元素!!!)


else(即在if判断不成立时进入else语句!!) 即当前节点存在孩子节点或者孩子节点还未被访问完!!

这里的思想就类似于前序遍历的思想了,只是没有前序遍历的 右节点存在,右节点入栈之后,左节点存在,左节点入栈,接着先入栈的后处理,后入栈的先处理的思想马上出站,而是要在满足我们的if条件才会进行出栈


gif演示:

20191016224243193.gif


希望大家能通过本篇博客掌握 树的三中遍历方式.


谢谢观看。?


目录
相关文章
|
5月前
|
存储 机器学习/深度学习 监控
网络管理监控软件的 C# 区间树性能阈值查询算法
针对网络管理监控软件的高效区间查询需求,本文提出基于区间树的优化方案。传统线性遍历效率低,10万条数据查询超800ms,难以满足实时性要求。区间树以平衡二叉搜索树结构,结合节点最大值剪枝策略,将查询复杂度从O(N)降至O(logN+K),显著提升性能。通过C#实现,支持按指标类型分组建树、增量插入与多维度联合查询,在10万记录下查询耗时仅约2.8ms,内存占用降低35%。测试表明,该方案有效解决高负载场景下的响应延迟问题,助力管理员快速定位异常设备,提升运维效率与系统稳定性。
285 4
|
10月前
|
存储 机器学习/深度学习 算法
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty 敏感词
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty 敏感词
KMP、Trie树 、AC自动机‌ ,三大算法实现 优雅 过滤 netty  敏感词
|
8月前
|
监控 算法 安全
基于 C# 基数树算法的网络屏幕监控敏感词检测技术研究
随着数字化办公和网络交互迅猛发展,网络屏幕监控成为信息安全的关键。基数树(Trie Tree)凭借高效的字符串处理能力,在敏感词检测中表现出色。结合C#语言,可构建高时效、高准确率的敏感词识别模块,提升网络安全防护能力。
210 2
|
10月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
252 17
|
10月前
|
存储 监控 算法
局域网上网记录监控的 C# 基数树算法高效检索方案研究
在企业网络管理与信息安全领域,局域网上网记录监控是维护网络安全、规范网络行为的关键举措。随着企业网络数据量呈指数级增长,如何高效存储和检索上网记录数据成为亟待解决的核心问题。基数树(Trie 树)作为一种独特的数据结构,凭借其在字符串处理方面的卓越性能,为局域网上网记录监控提供了创新的解决方案。本文将深入剖析基数树算法的原理,并通过 C# 语言实现的代码示例,阐述其在局域网上网记录监控场景中的具体应用。
217 7
|
12月前
|
人工智能 算法 语音技术
Video-T1:视频生成实时手术刀!清华腾讯「帧树算法」终结闪烁抖动
清华大学与腾讯联合推出的Video-T1技术,通过测试时扩展(TTS)和Tree-of-Frames方法,显著提升视频生成的连贯性与文本匹配度,为影视制作、游戏开发等领域带来突破性解决方案。
399 4
Video-T1:视频生成实时手术刀!清华腾讯「帧树算法」终结闪烁抖动
|
9月前
|
机器学习/深度学习 算法 搜索推荐
决策树算法如何读懂你的购物心理?一文看懂背后的科学
"你为什么总能收到刚好符合需求的商品推荐?你有没有好奇过,为什么刚浏览过的商品就出现了折扣通知?
262 0
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
374 3
 算法系列之数据结构-Huffman树
|
存储 自然语言处理 数据库
【数据结构进阶】AVL树深度剖析 + 实现(附源码)
在深入探讨了AVL树的原理和实现后,我们不难发现,这种数据结构不仅优雅地解决了传统二叉搜索树可能面临的性能退化问题,还通过其独特的平衡机制,确保了在任何情况下都能提供稳定且高效的查找、插入和删除操作。
848 19
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
369 59

热门文章

最新文章