要求

  • 二叉树的前序遍历

实现

  • 递归

  • 栈模拟

        

  • 定义结构体 Command 模拟指令,字符串s描述命令,树节点node为指令作用的节点
  • 定义栈 Stack 存储命令
 1 #include <iostream>
2 #include <vector>
3 #include <stack>
4 #include <cassert>
5
6 using namespace std;
7
8 struct TreeNode{
9 int val;
10 TreeNode* left;
11 TreeNode* right;
12 TreeNode(int x): val(x), left(NULL), right(NULL){}
13 };
14
15 //模拟指令,go--访问,print--输出
16 struct Command{
17 string s;
18 TreeNode* node;
19 Command(string s, TreeNode* node):s(s), node(node){}
20 };
21
22 class Solution{
23 public:
24 vector<int> preorderTraversal(TreeNode* root){
25 vector<int> res;
26 if( root == NULL )
27 return res;
28
29 stack<Command> stack;
30 stack.push( Command("go",root) );
31
32 while( !stack.empty() ){
33
34 Command command = stack.top();
35 stack.pop();
36
37 if( command.s == "print" )
38 res.push_back( command.node -> val);
39 else{
40 assert( command.s == "go" );
41 if( command.node -> right )
42 stack.push( Command("go",command.node->right));
43 if( command.node -> left)
44 stack.push( Command("go",command.node->left));
45 stack.push( Command("print",command.node));
46 }
47 }
         return res;
48 }
49 };
50
51 void print_vec(const vector<int>& vec){
52 for(int e:vec)
53 cout<<e<<" ";
54 cout<<endl;
55 }
56
57 int main(){
58 TreeNode* root = new TreeNode(1);
59 root->right = new TreeNode(2);
60 root->right->left = new TreeNode(3);
61 vector<int> res = Solution().preorderTraversal(root);
62 print_vec(res);
63
64 return 0;
65 }

结果

1-2-3

总结

  • 模拟了操作系统中方法栈的实现
  • 入栈顺序与实际执行顺序相反
  • 操作指令,而不是操作对象,把对象的指针封装在指令中
  • LeetCode 94为模拟中序遍历,145为模拟后序遍历
  • 本程序可以很容易地改写为中序和后序,而课本中的写法很难改写

-----------------------------------------------

栈模拟中序遍历

  • Python
 1 class Stack(object):
2 def __init__(self, size_limit = None):
3 self._size_limit = size_limit
4 self.elements = []
5 self._size = 0
6
7 def push(self, value):
8 if self._size_limit is not None and len(self.elements) > self._size_limit:
9 raise IndexError("Stack is full")
10 else:
11 self.elements.append(value)
12 self._size += 1
13
14 def top(self):
15 return self.elements[-1]
16
17 def pop(self):
18 val = self.elements.pop()
19 self._size -=1
20 return val
21
22 def is_empty(self):
23 return self._size == 0
24
25
26 class Node:
27 def __init__(self, val):
28 self.val = val
29 self.lchild = None
30 self.rchild = None
31 self.flag = True
32
33 def dfs(node):
34 if node is None:
35 return
36 dfs(node.lchild)
37 print(node.val)
38 dfs(node.rchild)
39
40 def dfs1(node):
41 stack = Stack()
42 stack.push(node)
43 while not stack.is_empty():
44 tmp = stack.top()
45 while tmp.flag and tmp.lchild is not None:
46 tmp.flag = False
47 stack.push(tmp.lchild)
48 tmp = tmp.lchild
49 tmp = stack.pop()
50 print(tmp.val)
51 if tmp.rchild is not None:
52 stack.push(tmp.rchild)
53
54 def dfs2(node):
55 stack = Stack()
56 tmp = node
57 while tmp is not None or not stack.is_empty():
58 while tmp is not None:
59 stack.push(tmp)
60 tmp = tmp.lchild
61 tmp = stack.pop()
62 print(tmp.val)
63 tmp = tmp.rchild
64
65 root = Node(0)
66 node1 = Node(1)
67 root.lchild = node1
68 node2 = Node(2)
69 root.rchild = node2
70 node3 = Node(3)
71 node1.lchild = node3
72 node4 = Node(4)
73 node1.rchild = node4
74 node5 = Node(5)
75 node2.rchild = node5
76
77 dfs(root)
78 dfs1(root)
79 dfs2(root)

>> 3 1 4 0 2 5

    • dfs是常规递归思路
    • dfs1增加了一个flag变量,判断节点是否访问过,不加会导致死循环
    • dfs2调整了思路,不用flag变量
  • c++方法1
 1 class Solution {
2
3 public:
4 vector<int> inorderTraversal(TreeNode* root) {
5
6 vector<int> res;
7 if( root == NULL )
8 return res;
9
10 stack<TreeNode*> stack;
11 TreeNode* cur = root;
12 while(cur != NULL || !stack.empty()){
13
14 if(cur != NULL){
15 stack.push(cur);
16 cur = cur->left;
17 }
18 else {
19 cur = stack.top();
20 stack.pop();
21 res.push_back(cur->val);
22 cur = cur->right;
23 }
24 }
25 return res;
26 }
27 };
  • c++方法2
 1 class Solution {
2
3 public:
4 vector<int> inorderTraversal(TreeNode* root) {
5
6 vector<int> res;
7 if( root == NULL )
8 return res;
9
10 stack<TreeNode*> stack;
11 TreeNode* cur = root;
12 while(cur != NULL || !stack.empty()){
13
14 while(cur != NULL){
15 stack.push(cur);
16 cur = cur->left;
17 }
18
19 cur = stack.top();
20 stack.pop();
21 res.push_back(cur->val);
22 cur = cur->right;
23
24 }
25 return res;
26 }
27 };

总结

  • 默认的访问顺序是从左到右,意味着左节点优先访问
  • 中序遍历的定义是,从左节点返回时输出,这就意味着如果都是左节点,节点是从下到上输出的(后进先出),故想到利用栈实现;如果都是右节点,则节点从上到下输出,此时需控制栈,使元素不堆积
  • 想清楚了怎么处理左节点,怎么处理右节点,如何移动指针,如何利用栈,就可以写代码了
  • 左节点优先访问反映在代码上就是指针指向左节点的语句在指针指向右节点之前,中序遍历反映在代码上就是节点先入栈出栈再输出
  • 方法2表面上是两层循环,其实内外循环执行次数加起来和方法1是一样的,两种算法时间复杂度取决于节点个数,都是O(n)
  • 方法1的逻辑更顺畅,方法2利用了左节点优先的规则,将左节点连续出现的循环内移,在左节点连续出现的情况下执行效率更高(少一次判断),可看做方法1的优化

[刷题] 144 Binary Tree Preorder Traversal的更多相关文章

  1. 二叉树前序、中序、后序非递归遍历 144. Binary Tree Preorder Traversal 、 94. Binary Tree Inorder Traversal 、145. Binary Tree Postorder Traversal 、173. Binary Search Tree Iterator

    144. Binary Tree Preorder Traversal 前序的非递归遍历:用堆来实现 如果把这个代码改成先向堆存储左节点再存储右节点,就变成了每一行从右向左打印 如果用队列替代堆,并且 ...

  2. C++版 - LeetCode 144. Binary Tree Preorder Traversal (二叉树先根序遍历,非递归)

    144. Binary Tree Preorder Traversal Difficulty: Medium Given a binary tree, return the preorder trav ...

  3. 【LeetCode】144. Binary Tree Preorder Traversal (3 solutions)

    Binary Tree Preorder Traversal Given a binary tree, return the preorder traversal of its nodes' valu ...

  4. [LeetCode] 144. Binary Tree Preorder Traversal 二叉树的先序遍历

    Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binary tr ...

  5. 刷题94. Binary Tree Inorder Traversal

    一.题目说明 题目94. Binary Tree Inorder Traversal,给一个二叉树,返回中序遍历序列.题目难度是Medium! 二.我的解答 用递归遍历,学过数据结构的应该都可以实现. ...

  6. 【LeetCode】144. Binary Tree Preorder Traversal

    题目: Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binar ...

  7. Java for LeetCode 144 Binary Tree Preorder Traversal

    Given a binary tree, return the preorder traversal of its nodes' values. For example: Given binary t ...

  8. 144. Binary Tree Preorder Traversal

    Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binary tr ...

  9. leetcode 144. Binary Tree Preorder Traversal ----- java

    Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binary tr ...

随机推荐

  1. Redis 超详细自动管理Cluster集群工具上手 redis-trib.rb (多图,手把手)

    安装介绍 ​ redis-trib.rb是一款由Redis官方提供的集群管理工具,能够大量减少集群搭建的时间. ​ 除此之外,还能够简化集群的检查.槽迁徙.负载均衡等常见的运维操作,但是使用前必须要安 ...

  2. 前端学习 node 快速入门 系列 —— 报名系统 - [express]

    其他章节请看: 前端学习 node 快速入门 系列 报名系统 - [express] 最简单的报名系统: 只有两个页面 人员信息列表页:展示已报名的人员信息列表.里面有一个报名按钮,点击按钮则会跳转到 ...

  3. PaddleOCR详解

    @ 目录 PaddleOCR简介 环境配置 PaddleOCR2.0的配置环境 Docker 数据集 文本检测 使用自己的数据集 文本识别 使用自己的数据集 字典 自定义字典 添加空格类别 文本角度分 ...

  4. java面试-死锁产生、定位分析和修复

    死锁发生:两个或多个线程之间,互相持有对方需要的锁,而永久处于阻塞状态 一.手写死锁代码: public class DeadLockSample extends Thread { private S ...

  5. 【1.0 Regular Expressions 正则表达式】

    [概念] RegEx 正则表达式是一种特殊的字符序列,可帮助您使用专门的模板语法,来匹配对应的匹配方法或字符串组 它们可用于搜索,编辑或操纵文本和数据 正则表达式通常用于验证输入和检索信息 比如我们要 ...

  6. 透视HTTP协议,带你拨开纷繁复杂的表象

    一个HTTP,打趴80%面试者! HTTP是一个在计算机世界里专门在两点之间传输文字.图片.音频.视频等超文本数据的约定和规范.如果你不懂HTTP协议,那就相当于是个只有半桶水的程序员. 在这个专栏中 ...

  7. python3使用myqr生成链接二维码

    技术背景 二维码技术在各个领域中都已经有非常成熟的应用,比如随处可见的二维码支付,比如疫情期间的绿码,再比如工业领域中,可以使用二维码作为定位的标签,大大提升了室内定位技术的精确度.二维码的格式内容大 ...

  8. Java(215-231)【Object类、常用API】

    1.Object类的toString方法 java.lang.Object 类 Object 是类层次结构的根(父)类. 每个类(Person,Student...)都使用 Object 作为超(父) ...

  9. Scrapy入门到放弃01:开启爬虫2.0时代

    前言 Scrapy is coming!! 在写了七篇爬虫基础文章之后,终于写到心心念念的Scrapy了.Scrapy开启了爬虫2.0的时代,让爬虫以一种崭新的形式呈现在开发者面前. 在18年实习的时 ...

  10. 测试报告模板:HTMLTestRunner.py(新版)

    报告样式效果: 报告源码:HTMLTestRunner.py 1 """ 2 A TestRunner for use with the Python unit test ...