• [刷题] 144 Binary Tree Preorder Traversal


    要求

    • 二叉树的前序遍历

    实现

    • 递归

    • 栈模拟

               

    • 定义结构体 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的优化
  • 相关阅读:
    中译英6
    中译英5
    中译英4
    B5
    BEC listen and translation exercise 37
    BEC listen and translation exercise 36
    中译英2
    PyQt(Python+Qt)学习随笔:Designer中ItemViews类部件的frameShadow属性
    第15.16节 PyQt(Python+Qt)入门学习:PyQt中的信号(signal)和槽(slot)机制以及Designer中的使用
    PyQt(Python+Qt)学习随笔:Designer中ItemViews类部件frameShape属性
  • 原文地址:https://www.cnblogs.com/cxc1357/p/12388632.html
Copyright © 2020-2023  润新知