二叉树的前序中序后序遍历(当然是非递归的!)

本文介绍了二叉树的前序、中序和后序非递归遍历方法,通过栈结构模拟递归过程,实现了遍历算法的非递归版本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树的三种遍历方式一直都是为人津津乐道的面试题,考察一个人对递归的理解让他写个三种遍历方式是最简单的考察方式了,那么考察一个人对递归的理解更加深层次的方式就是让他用循环模拟递归(就是把递归代码转换成非递归),一般想要实现这样的东西是需要栈的,或许说使用栈的结构更加贴合函数栈的压入和弹出,更加好理解

递归的三种遍历方式分别为,前序遍历,中序遍历,后序遍历,在考虑完了递归的写法之后,非递归的写法更加难;
  • 因为前序遍历是首先访问根节点的,所以见到节点就访问,然后再去访问左孩子和右孩子。原先使用递归的方式,栈帧的模拟可以使用栈来实现,因为是先访问了左节点,所以左节点应该在右节点之后入栈b不难写出下面的代码
     1 void PreOrder_NonR()
     2 
     3                 {
     4 
     5                                  if (_root == NULL )
     6 
     7                                 {
     8 
     9                                                  return;
    10 
    11                                 }
    12 
    13                                  stack<BinaryTreeNode <T>*> s;
    14 
    15                                 s.push(_root);
    16 
    17                                  while (!s.empty())
    18 
    19                                 {
    20 
    21                                                  BinaryTreeNode<T >* top = s.top();
    22 
    23                                                 cout << top->_data << " " ;
    24 
    25                                                 s.pop();
    26 
    27                                                  if (top->_right)
    28 
    29                                                 {
    30 
    31                                                                 s.push(top->_right);
    32 
    33                                                 }
    34 
    35                                                  if (top->_left)
    36 
    37                                                 {
    38 
    39                                                                 s.push(top->_left);
    40 
    41                                                 }
    42 
    43                                 }
    44 
    45                                 cout << endl;
    46 
    47                 }

     

  • 中序遍历可以采用递归的思考方式,因为中序遍历的方式是在访问完左子树之后再去访问根节点,所以在访问完根节点之后进入右子树,右子树又相当于一个新的根节点,所以应该采取访问完根节点之后将右孩子立刻压入栈,然后进入循环可以写出下面的代码
     1 void InOrder_NonR()
     2 
     3                 {
     4 
     5                                  stack<BinaryTreeNode <T>*> s;
     6 
     7                                  BinaryTreeNode<T > *cur = _root;
     8 
     9                                  while (cur || !s.empty())
    10 
    11                                 {
    12 
    13                                                  while (cur)
    14 
    15                                                 {
    16 
    17                                                                 s.push(cur);
    18 
    19                                                                 cur = cur->_left;
    20 
    21                                                 }
    22 
    23                                                  if (!s.empty())
    24 
    25                                                 {
    26 
    27                                                                  BinaryTreeNode<T > *top = s.top();
    28 
    29                                                                 cout << top->_data << " " ;
    30 
    31                                                                 s.pop();
    32 
    33                                                                 cur = top->_right;
    34 
    35                                                 }
    36 
    37                                 }
    38 
    39                                 cout << endl;
    40 
    41                 }

     

  • 后序遍历是先访问左子树和右子树,所以当左孩子出栈的时候,下一个栈内节点(即根节点)不能立刻就访问,需要考虑几种情况,如果此时此刻右孩子为空,那么可以访问,如果此时有孩子不为空,那么需要考虑右孩子是否被访问过了,如果访问过了,则可以访问根节点,否则需要先访问右子树然后再去访问根节点,可以利用一个变量来保存之前访问的是哪一个节点可以写出如下代码
 1  void PostOrder_NonR()
 2 
 3                 {
 4 
 5                                  stack<BinaryTreeNode <T> *> s;
 6 
 7                                  BinaryTreeNode<T >* PreVisited = NULL;
 8 
 9                                  BinaryTreeNode<T >* cur = _root;
10 
11                                  while (cur || !s.empty())
12 
13                                 {
14 
15                                                  while (cur)
16 
17                                                 {
18 
19                                                                 s.push(cur);
20 
21                                                                 cur = cur->_left;
22 
23                                                 }
24 
25                                                  BinaryTreeNode<T > *top = s.top();
26 
27                                                  if (top->_right == NULL || PreVisited == top->_right)
28 
29                                                 {
30 
31                                                                 cout << top->_data << " " ;
32 
33                                                                 s.pop();
34 
35                                                                 PreVisited = top;
36 
37                                                 }
38 
39                                                  else
40 
41                                                 {
42 
43                                                                 cur = top->_right;
44 
45                                                 }
46 
47                                 }
48 
49                                 cout << endl;
50 
51                 }

这是我从我的笔记导出来的,话说缩进怎么变成这德行了。。。

              
内容概要:本文深入探讨了Kotlin语言在函数式编程跨平台开发方面的特性优势,结合详细的代码案例,展示了Kotlin的核心技巧应用场景。文章首介绍了高阶函数Lambda表达式的使用,解释了它们如何简化集合操作回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程跨平台开发领域不断完善发展。; 适合人群:对函数式编程跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解实践Kotlin的函数式编程特性跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解掌握。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值