[Alg] 二叉树的非递归遍历

1. 非递归遍历二叉树算法 (使用stack)

以非递归方式对二叉树进行遍历的算法需要借助一个栈来存放访问过得节点。

(1) 前序遍历

从整棵树的根节点开始,对于任意节点V,访问节点V并将节点V入栈,并判断节点V的左子节点L是否为空。若L不为空,则将L置为当前节点V;若L为空,则取出栈顶节点,并将栈顶结点的右子节点置为当前节点V。重复上述操作,直到当前节点V为空并且栈为空,遍历结束。

(2) 中序遍历

从整棵树的根节点开始,对于任意节点V,判断其左子节点L是否为空。若L不为空,则将V入栈并将L置为当前节点V;若L为空,则取出栈顶节点并访问该栈顶节点,然后将其右子节点置为当前节点V。重复上述操作,直到当前节点V为空节点且栈为空,遍历结束。

(3) 后序遍历

首先将整颗二叉树的根节点入栈。取栈顶节点V,若V不存在左子节点和右子节点,或V存在左子节点或右子节点但其左子节点和右子节点都被访问过了,则访问节点V,并将V从栈中弹出。若非上述两种情况,则将V的右子节点和左子节点(注意先右后左,这样出栈时才能先左后右)依次入栈。重复上述操作,直到栈为空,遍历结束。

2. 二叉树递归与非递归遍历代码

  1 #include "stdafx.h"
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 
  6 
  7 #define Stack_increment 20
  8 #define Stack_Size 100  
  9 
 10 
 11 typedef struct  Tree
 12 {
 13     char data;
 14     struct Tree *lchild;
 15     struct Tree *rchild;
 16 }Node;
 17 
 18 Node* createBinaryTree()
 19 {
 20     Node *root;
 21     char ch;
 22     scanf("%c", &ch);
 23 
 24     if (ch == '#')
 25     {
 26         root = NULL;
 27     }
 28     else
 29     {
 30         root = (Node *)malloc(sizeof(Node));
 31         root -> data = ch;
 32         root -> lchild = createBinaryTree();
 33         root -> rchild = createBinaryTree();        
 34     }
 35 
 36     return root;
 37 }
 38 
 39 typedef struct 
 40 {
 41     int top;
 42     Node* arr[Stack_Size]; 
 43 }Stacktree;
 44 
 45 void InitStack(Stacktree *S)
 46 {
 47     S->top = 0;
 48 }
 49 
 50 void Push(Stacktree* S, Node* x)
 51 {
 52     int top1 = S -> top;
 53     if (x -> data == '#')
 54     {
 55         return;
 56     }
 57     else
 58     {
 59         S -> arr[top1++] = x;
 60         S -> top++;
 61     }
 62 }
 63 
 64 int Pop(Stacktree *S)
 65 {
 66     int top = S -> top;
 67     if (S->top == 0)
 68     {
 69         return 0;
 70     }
 71     else
 72     {
 73         --(S->top);
 74         return 1;
 75     }
 76 }
 77 
 78 Node* GetTop(Stacktree *S)
 79 {
 80     int top1 = S -> top;
 81     Node*p;
 82     p = S -> arr[top1--];
 83     return p;
 84 }
 85 
 86 Node* GetTop1(Stacktree *S)
 87 {
 88     int top1 = S -> top;
 89     Node*p;
 90     top1--;
 91     p = S -> arr[top1];
 92     return p;
 93 }
 94 
 95 int IsEmpty(Stacktree *S)
 96 {
 97     return(S->top == 0 ? 1 : 0);
 98 }
 99 
100 void preorderRecursive(Node *p )
101 {
102     if (p != NULL)
103     {
104         printf("%c ", p -> data);
105         preorderRecursive(p -> lchild);
106         preorderRecursive(p -> rchild);
107     }
108 }
109 
110 void inorderRecursive(Node *p )
111 {
112     if (p != NULL)
113     {
114         inorderRecursive(p -> lchild);
115         printf("%c ", p -> data);
116         inorderRecursive(p -> rchild);
117     }
118 }
119 
120 void postorderRecursive(Node *p )
121 {
122     if (p != NULL)
123     {
124         postorderRecursive(p -> lchild);
125         postorderRecursive(p -> rchild);
126         printf("%c ", p -> data);
127     }
128 }
129 
130 void preordernotRecursive(Node *p)
131 {
132     if(p)
133     {
134         Stacktree stree ;
135         InitStack(&stree);
136         Node *root = p;
137         while(root != NULL || !IsEmpty(&stree))
138         {
139             while(root != NULL)
140             {
141                 printf("%c  ", root->data);
142                 Push(&stree, root);
143                 root = root -> lchild;
144             }
145 
146             if(!IsEmpty(&stree))
147             {
148                 Pop(&stree);
149                 root = GetTop(&stree);
150                 root = root -> rchild;
151             }
152         }
153     }
154 }
155 
156 void inordernotRecursive(Node *p)
157 {
158     if(p)
159     {
160         Stacktree stree;
161         InitStack(&stree);
162         Node *root = p;
163         while(root != NULL || !IsEmpty(&stree))
164         {
165             while(root != NULL)
166             {
167                 Push(&stree, root);
168                 root = root -> lchild;
169             }
170 
171             if(!IsEmpty(&stree))
172             {
173                 Pop(&stree);
174                 root = GetTop(&stree);
175                 printf("%c  ", root -> data);
176                 root = root -> rchild;
177             }
178         }
179     }
180 }
181 
182 void postordernotRecursive(Node *p)
183 {
184     Stacktree stree;
185     InitStack(&stree);
186 
187     Node *root;    
188     Node *pre = NULL;    
189 
190     Push(&stree, p);
191 
192     while (!IsEmpty(&stree))
193     {
194         root = GetTop1(&stree);
195 
196         if ((root -> lchild == NULL && root -> rchild == NULL) || (pre != NULL && (pre == root -> lchild || pre == root -> rchild)))
197         {
198             printf("%c ", root -> data);
199             Pop(&stree);
200             pre = root;
201         }
202 
203         else
204         {
205             if (root -> rchild != NULL)
206             {
207                 Push(&stree, root -> rchild);
208             }
209 
210             if (root -> lchild != NULL)
211             {
212                 Push(&stree, root -> lchild);
213             }
214         }
215 
216     }
217 }
218 
219 void main()
220 {
221 
222     printf("请输入二叉树,'#'为空\n");   
223     Node *root = createBinaryTree();
224 
225     printf("\n递归先序遍历:\n");
226     preorderRecursive(root);
227 
228     printf("\n递归中序遍历:\n");
229     inorderRecursive(root);
230 
231     printf("\n递归后序遍历:\n");
232     postorderRecursive(root);
233 
234     printf("\n非递归先序遍历\n");
235     preordernotRecursive(root);
236 
237     printf("\n非递归中序遍历\n");
238     inordernotRecursive(root);
239 
240     printf("\n非递归后序遍历\n");
241     postordernotRecursive(root);
242 
243     getchar();
244     getchar();
245 }

(代码中的top是栈顶元素的上一位的index,不是栈顶元素的index~)

input:

ABC##D##E##

output:

递归先序遍历:

A B C D E

递归中序遍历:

C B D A E

递归后序遍历:

C D B E A

非递归先序遍历:

A B C D E

非递归中序遍历:

C B D A E

非递归后序遍历:

C D B E A 

3. Morris Traversal (遍历二叉树无需stack)

Morris Traversal 是一种非递归无需栈仅在常量空间复杂度的条件下即可实现二叉树遍历的一种很巧妙的方法。该方法的实现需要构造一种新型的树结构,Threaded Binary Tree.

3.1 Threaded Binary Tree 定义

Threaded binary tree: A binary tree is threaded by making all right child pointers that would normally be null point to the inorder successor of the node (if it exists), and all left child pointers that would normally be null point to the inorder predecessor of the node. ~WIkipedia

Threaded binary tree 的构造相当于将所有原本为空的右子节点指向了中序遍历的该点的后续节点,把所有原本为空的左子节点都指向了中序遍历的该点前序节点。如图1所示。

那么通过这种方式,对于当前节点cur, 若其右子树为空,(cur -> right = NULL),那么通过沿着其pre指针,即可返回其根节点继续遍历。

比如对于图1中的节点A,其右孩子为空,则说明以A为根节点的子树遍历完成,沿着其pre指针可以回到A的根节点B,继续遍历。这里的pre指针相当于保存了当前节点的回溯的位置信息。

 

图1. Threaded binary tree         图2. Threaded tree构造及遍历算法图示

3.2 Threaded Binary Tree 算法实现

3.2.1 算法描述

1. 初始化指针cur = root

2. while (cur != NULL)

    2.1 if cur -> left == NULL

          a) print(cur -> val)

          b) cur = cur -> right

    2.2 else if cur -> left != NULL 

          将pre 指向cur 的左子树中的 最右子节点 (并保证不指回cur)

          2.2.1 if pre -> right == NULL

                   a) pre -> right = cur

                   b) cur = cur -> left

          2.2.2 else if pre -> right != NULL (说明pre -> right是用于指回cur节点的指针)

                   a) 将pre -> right 置空

      b) print(cur -> val)

         c) cur = cur -> right 

3.2.2 代码实现 (中序)

 1 # include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct TreeNode
 5 {
 6     int val;
 7     struct TreeNode *right;
 8     struct TreeNode *left;
 9     TreeNode(int x): val(x), left(NULL), right(NULL) {}
10 };
11 
12 vector<int> inorderTraversal(TreeNode *root)
13 {
14     vector<int> res;
15     if(!root) return res;
16     TreeNode *cur, *pre;
17     cur = root;
18 
19     while(cur)
20     {
21         if(cur -> left == NULL)
22         {
23             res.push_back(cur -> val);
24             cur = cur -> right;
25         }
26 
27         else if(cur -> left != NULL)
28         {
29             pre = cur -> left;
30             while(pre -> right && pre -> right != cur) pre = pre -> right;
31             if(pre -> right == NULL)
32             {
33                 pre -> right = cur;
34                 cur = cur -> left;
35             }
36             else if(pre -> right != NULL)
37             {
38                 pre -> right = NULL;
39                 res.push_back(cur -> val);
40                 cur = cur -> right;
41             }
42         }
43     }
44     return res;
45 }
46 
47 int main()
48 {
49     vector<int> res;
50     TreeNode *node1 = new TreeNode(1);
51     TreeNode *node2 = new TreeNode(2);
52     TreeNode *node3 = new TreeNode(3);
53     TreeNode *node4 = new TreeNode(4);
54     node1 -> left = node2;
55     node2 -> left = node3;
56     node3 -> right = node4;
57     inorderTraversal(node1);
58     res = inorderTraversal(node1);
59     vector<int>::iterator it;
60     for(it = res.begin(); it != res.end(); ++it)
61     {
62         cout << *it << " ";
63     }
64     cout << endl;
65     delete node1; delete node2;
66     delete node3; delete node4;
67     return 0;
68 }
69 
70 // 3 4 2 1

参考:

1. 以先序、中序、后序的方式递归非递归遍历二叉树:https://blog.csdn.net/asd20172016/article/details/80786186

2. Morris Traversal: [LeetCode] Binary Tree Inorder Traversal 二叉树的中序遍历: https://www.cnblogs.com/grandyang/p/4297300.html

3. [LeetCode] Recover Binary Search Tree 复原二叉搜索树: https://www.cnblogs.com/grandyang/p/4298069.html

4. Wikipedia: Threaded binary tree: https://en.wikipedia.org/wiki/Threaded_binary_tree

转载于:https://www.cnblogs.com/shiyublog/p/11256756.html

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

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

相关文章

[c++]访MSN浮出窗口的示例

【声明】严格来讲&#xff0c;这篇文章不属于我的原创。我在这里参考了codeproject上的国外作者的模仿MSN浮出窗口的C#代码。换句话说&#xff0c;可以认为我把C#代码翻译成了C代码。另外&#xff0c;为了简化代码&#xff0c;CloseButton我没有采用自己绘制&#xff0c;而是用…

mybatis学习(42):mybatis的一级缓存

目录结构 com.geyao.mybatis.mapper BlogMapper类 package com.geyao.mybatis.mapper;import java.util.List; import java.util.Map;import org.apache.ibatis.annotations.Param;import com.geyao.mybatis.pojo.Blog;public interface BlogMapper {Blog selectBlog(Integer…

防止ASP.NET按钮多次提交的办法

方法一<asp:Button ID"btnSumbit" runat"server" UseSubmitBehavior"false" OnClientClick"this.valueSumbit;this.disabledtrue; " Text"Sumbit" OnClick"btnSumbit_Click" /> 方法二1<html xmlns"…

mybatis学习(43):一级缓存被刷新情况

目录结构 com.geyao.mybatis.mapper BlogMapper类 package com.geyao.mybatis.mapper;import java.util.List; import java.util.Map;import org.apache.ibatis.annotations.Param;import com.geyao.mybatis.pojo.Blog;public interface BlogMapper {Blog selectBlog(Integer…

python文件读写小结

读文件 打开一个文件用open()方法(open()返回一个文件对象&#xff0c;它是可迭代的)&#xff1a; >>> f open(test.txt, r) r表示是文本文件&#xff0c;rb是二进制文件。&#xff08;这个mode参数默认值就是r&#xff09; 如果文件不存在&#xff0c;open()函数就会…

mybatis学习(44):二级缓存1

目录结构 com.geyao.mybatis.mapper BlogMapper类 package com.geyao.mybatis.mapper;import java.util.List; import java.util.Map;import org.apache.ibatis.annotations.Param;import com.geyao.mybatis.pojo.Blog;public interface BlogMapper {Blog selectBlog(Integer…

HDU6089 恐怖分子(变形线段树)

题目描述 n*m的平面内有K个不安全点&#xff0c;Q个询问位置在(x,y)的人能走到多少个点&#xff1f;从(x,y)走到(x,y)是合法的&#xff0c;当且仅当(x,y)和(x,y)之间的矩形中不包含不安全点。 题解 问题相当于平面中有若干障碍点&#xff0c;询问以某一个点为四个角之一的不包含…

mybatis学习(45):开启二级缓存

目录结构 com.geyao.mybatis.mapper BlogMapper类 package com.geyao.mybatis.mapper;import java.util.List; import java.util.Map;import org.apache.ibatis.annotations.Param;import com.geyao.mybatis.pojo.Blog;public interface BlogMapper {Blog selectBlog(Integer…

【读书笔记】重要的东西

以上摘自一本叫做《大道至简》的小册子&#xff0c;有关介绍可以参考下面的链接 http://www.china-pub.com/34356转载于:https://www.cnblogs.com/chenxizhang/archive/2008/08/11/1264917.html

七夕秀恩爱新姿势!这波操作我给十分!

一、前言 像每一滴酒回不了最初的葡萄&#xff0c;我回不到年少。爱情亦是如此&#xff0c;这就是写一篇小程序的初衷&#xff0c;用来记录我和她最美的恋爱。什么是最美恋爱&#xff1f;就是繁忙之余的一封书信&#xff0c;一起奋斗的目标&#xff0c;精彩的瞬间&#xff0c;旅…

mybatis学习(46):二级缓存被刷新的情况

目录结构 com.geyao.mybatis.mapper BlogMapper类 package com.geyao.mybatis.mapper;import java.util.List; import java.util.Map;import org.apache.ibatis.annotations.Param;import com.geyao.mybatis.pojo.Blog;public interface BlogMapper {Blog selectBlog(Integer…

python 主函数 输入

python 主函数 输入 看一段主函数调用函数的小程序&#xff1a; 1 import sys2 def Fuc():3 print hello4 5 if __name__ __main__:6 if len(sys.argv) ! 3:7 print Usage: python input_name output_name8 exit(1)9 f_input sys.argv[1] 10…

mybatis学习(47):嵌套查询--一对一

数据库 目录结构 映入jar包和junit单元测试 com.geyao.mybatis.mapper AuthorMapper类 package com.geyao.mybatis.mapper;import com.geyao.mybatis.pojo.Author; public interface AuthorMapper {Author selectAuthorById(Integer id); } BlogMapper类 package com.gey…

element-ui select

1. 组合 label <!DOCTYPE html> <html><head><meta charset"UTF-8"><!-- import CSS --><link rel"stylesheet" href"https://unpkg.com/element-ui/lib/theme-chalk/index.css"> </head><body>…

WEBSERVICE 之WSDL

使用WSDL生成SOAP请求 转载于:https://www.cnblogs.com/canlove/archive/2008/08/18/1270099.html

mybatis学习(48):列表信息查询

数据库 目录结构 映入jar包和junit单元测试 com.geyao.mybatis.mapper AuthorMapper类 package com.geyao.mybatis.mapper;import com.geyao.mybatis.pojo.Author; public interface AuthorMapper {Author selectAuthorById(Integer id); } BlogMapper类 package com.gey…

Pycharm中运行Python代码的几种方式

Pycharm中运行Python代码的几种方式 在pycharm中的Python代码运行会出现各种奇葩的问题&#xff0c;比如&#xff0c;密码输入时不显示或没有提示&#xff0c;给我们带来一些麻烦&#xff0c;下面介绍几种代码运行的几种方式&#xff1a; 一、直接运行&#xff08;Run按钮或者快…

mybatis学习(49):嵌套查询--一对多

数据库表 数据库叫blog_gp1701 author表 数据 blog表 数据 comment表 数据 post表 数据 目录结构 jar包导入 先给对应的jar包导入 建立一个junit单元测试 配置文件 log4j.properties ### \u914D\u7F6E\u6839 ### log4j.rootLogger debug,console ,fileAppender,dailyRo…

诗词歌赋,样样精通!诗词古语小程序带你领略魅力古风丨实战

1. 小程序功能 古诗词大全成语大全成语接龙诗词飞花令诗词分享、收藏诗词接龙唐诗宋词起名字百家姓猜谜语2. 小程序预览&#xff1a; 3. 部分截图 首页 列表页 详情页 分享页 唐诗宋词 成语接龙 4. 项目结构 . ├── README.md ├── project.config.json …

mybatis学习(50):嵌套查询

数据库表 数据库叫blog_gp1701 author表 数据 blog表 数据 comment表 数据 post表 数据 目录结构 jar包导入 先给对应的jar包导入 建立一个junit单元测试 配置文件 log4j.properties ### \u914D\u7F6E\u6839 ### log4j.rootLogger debug,console ,fileAppender,dailyRo…