要求

  • 二叉树的前序遍历

实现

  • 递归

  • 栈模拟

        

  • 定义结构体 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. [Kong 与 Konga 与 Postgres数据库] 之 Kuberneres 部署

    1.Kong的概述 Kong是一个clould-native.快速的.可扩展的.分布式的微服务抽象层(也称为API网关.API中间件或在某些情况下称为服务网格)框架.Kong作为开源项目在2015年推 ...

  2. GitlabCI/CD&Kubernetes项目交付流水线实践

    GitlabCI实践 GitLabCI/CD基础概念 为什么要做CI/CD? GitLab CI/CD简介 GitLabCI VS Jenkins 安装部署GitLab服务 GitLabRunner实 ...

  3. 以聊天的形式解决traefik2.1.X的一个问题

    海口-老男人 17:24:48 大哥,这个是啥报错呀 海口-老男人 17:27:04 E0413 09:23:13.134144 1 reflector.go:153] pkg/mod/k8s.io/ ...

  4. jq分页功能。

    最近在写官网的分页功能.在网上找了很多案例都太复杂也太重.所以准备写一个简单一点的分页. 需求:把请求到的数据做分页. 准备:使用了网上一个简单的分页插件. 思路:分页相当于tab切换功能.具体实操把 ...

  5. OO_Unit4暨学期总结

    OO_Unit4暨学期总结 一.本单元架构设计 1.1 第13次作业架构设计 就我个人而言,这次作业应该是本单元难度最大的一次作业,原因在于陡然转向UML后,对UML各个元素的关系理解需要先下一番功夫 ...

  6. 使用VS Code从零开始开发调试.NET 5

    使用VS Code 从零开始开发调试.NET 5.无需安装VS 2019即可开发调试.NET 5应用. VS Code 全称是 Visual Studio Code,Visual Studio Cod ...

  7. @Transactional+@Autowired出现的lateinit property xx has not been initialized错误

    1 问题描述 用Kotlin编写Spring Boot,在业务层中使用@Transactional+@Autowired时出现如下错误: lateinit property dao has not b ...

  8. Erda MSP 系列 - 以服务观测为中心的 APM 系统设计:开篇词

    本文首发于 Erda 技术团队知乎账号,更多技术文章可点击 Erda 技术团队 作者:刘浩杨,端点科技 PaaS 技术专家,微服务治理和监控平台负责人,Apache SkyWalking PMC成员 ...

  9. 编写shell脚本让springboot项目在CentOS中开机自启动

    springboot项目部署在CentOS系统上时,如果遇到停电关机,公司的实施人员就得跑到甲方现场重新启动项目并测试,很是麻烦,这里探讨如何编写shell脚本控制springboot项目开机时自动启 ...

  10. C/C++ 进程代码注入与提权/降权

    如果将shellcode注入到具有特定权限的进程中,我们就可以获得与该进程相同的权限,此方法可以用于提权与降权操作,注入有多种方式,最简单的是直接将metasploit生成的有效载荷直接注入到目标进程 ...