• 二叉树遍历(前序、中序、后序)的递归及非递归实现(小结)


    先写点最基本的知识

    前序遍历: 
        1.访问根节点 
        2.前序遍历左子树 
        3.前序遍历右子树 
    中序遍历: 
        1.中序遍历左子树 
        2.访问根节点 
        3.中序遍历右子树 
    后序遍历: 
        1.后序遍历左子树 
        2.后序遍历右子树 
        3.访问根节点

    递归实现是很容易地,可以参考《算法导论》上的写法

     1 //遍历
     2 //前序、中序、后序遍历
     3 PREVORDER-TREE-WALK(x)
     4   if x != NIL
     5      then print key[x]
     6           PREVORDER-TREE-WALK(left[x])          
     7           PREVORDER-TREE-WALK(right[x])
     8 //中序
     9 INORDER-TREE-WALK(x)
    10   if x != NIL
    11      then INORDER-TREE-WALK(left[x])
    12           print key[x]
    13           INORDER-TREE-WALK(right[x])
    14 //后序
    15 POST-TREE-WALK(x)
    16   if x != NIL 
    17      then POST-TREE-WALK(left[x])
    18           POST-TREE-WALK(right[x])
    19           print key[x]

    但看到这篇博文(程序员基本功之遍历二叉树)中的写法,感觉很舒服,也拿过来

    1 def VisitTree_Recursive(root, order):
    2   if root:
    3     if order == 'NLR': print(root.data)
    4     VisitTree_Recursive(root.left, order)
    5     if order == 'LNR': print(root.data)
    6     VisitTree_Recursive(root.right, order)
    7     if order == 'LRN': print(root.data)

    上面都是铺垫,递归写法很简单,面试中也不会被问到,会拿来做问题的是非递归写法。感觉(程序员基本功之遍历二叉树)这篇博文对思路的分析非常清楚,也拿过来

    非递归的前序、中序遍历

    如果不用递归呢?实际上我们要做的就是自己维护一个栈(数据结构)来保存需要但尚未来得及处理的数据。

    前序和中序都是非常简单的,当遇到一个非空的根结点时,打印其数据(如果是前序遍历),并将其压栈,然后递归地(这里用循环来模拟递归)处理其左子结点;当没有左子结点时,从栈中弹出之前遇到的某个根结点(它没有做子结点,或者左子结点已经处理完毕,需要再处理右子结点),打印数据(如果是中序遍历),然后继续处理右子结点。同样地,把两种遍历方式写在一起以便比较。

     1 def VisitTree(root, order):
     2   s = []
     3   while root or s:
     4     if root:
     5       if order == 'NLR': print(root.data)
     6       s.append(root)
     7       root = root.left
     8     else:
     9       root = s.pop()
    10       if order == 'LNR': print(root.data)
    11       root = root.right

    博主的python代码果然是清晰易懂,但看到的另外一篇文章(二叉树的非递归前序、中序以及后序遍历C++模版类实现)给出了实现代码,感觉更爽,代码拿过来。

    这是基于模板实现的Stack类

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 //Author: 过往记忆
     6 //Blog: www.wypblog.com
     7 //Email: wyphao.2007@163.com
     8 ///////////////////////////////////////////////////////////////////////
     9 //stack 
    10 template <class T>
    11 class Stack{
    12 public:
    13     Stack(int size = 50);
    14     ~Stack();
    15     void push(T* data);
    16     T* pop();
    17     bool isEmpty();
    18     T* peek();
    19 private:
    20     int size;
    21     int top;
    22     bool isFull();
    23     T **data;
    24 };
    25 
    26 template <class T>
    27 Stack<T>::Stack(int size){
    28     if(size <= 0){
    29         cout << "分配的内存太小了" << endl; 
    30     }
    31     
    32     data = new T*[size];
    33     top = -1;
    34     this->size = size; 
    35 }
    36 
    37 template <class T>
    38 Stack<T>::~Stack(){
    39     delete []data;
    40 }
    41 
    42 template <class T>
    43 void Stack<T>::push(T* data){
    44     ++top;
    45     if(isFull()){
    46         cout << "貌似栈满了耶" << endl;
    47         exit(1); 
    48     } 
    49     this->data[top] = data; 
    50 } 
    51 
    52 template <class T>
    53 T* Stack<T>::pop(){ 
    54     if(isEmpty()){
    55         cout << "栈为空,不可以再出元素了!" << endl;
    56         exit(1); 
    57     }
    58     
    59     return data[top--]; 
    60 }
    61 
    62 template <class T>
    63 T* Stack<T>::peek(){
    64     if(isEmpty()){
    65         cout << "栈为空" << endl;
    66         exit(1); 
    67     }
    68     
    69     return data[top];
    70 }
    71 
    72 template <class T>
    73 bool Stack<T>::isFull(){
    74     if(top == size){
    75         return true; 
    76     } 
    77     
    78     return false; 
    79 } 
    80 
    81 template <class T>
    82 bool Stack<T>::isEmpty(){
    83     if(top < 0){
    84         return true; 
    85     } 
    86     
    87     return false; 
    88 } 

    下面是使用此Stack实现的非递归版本遍历

     1 template <class T> 
     2 class BTree{
     3 public:
     4     BTree *left;
     5     BTree *right;
     6     T data; 
     7     
     8     BTree() : left(NULL), right(NULL), data(NULL){};
     9     ~BTree(){}; 
    10 }; 
    11 
    12 ///////////////////////////////////////////////////////////////////////
    13 template <class T> 
    14 void PreOrder(BTree<T> *root){
    15     if(root != NULL){
    16         Stack<BTree<T> > stack ;
    17         BTree<T> *ptr = root;
    18         BTree<T> *temp; 
    19         stack.push(ptr);
    20         while(!stack.isEmpty())    {
    21             temp =  stack.pop(); 
    22             cout << temp->data << " ";
    23             if(temp->right != NULL){
    24                 stack.push(temp->right);
    25             }
    26             
    27             if(temp->left != NULL){
    28                 stack.push(temp->left);
    29             }
    30         }
    31         cout << endl; 
    32     } 
    33 } 
    34 
    35 ///////////////////////////////////////////////////////////////////////
    36 template <class T>
    37 void InOrder(BTree<T> *root){
    38     if(root != NULL){
    39         Stack<BTree<T> > stack ;
    40         BTree<T> *ptr = root;
    41         while(!stack.isEmpty() || ptr != NULL){
    42             while(ptr != NULL){
    43                 stack.push(ptr);
    44                 ptr = ptr->left;
    45             }
    46             
    47             if(!stack.isEmpty()){
    48                 ptr = stack.pop();
    49                 cout << ptr->data << " ";
    50                 ptr = ptr->right;
    51             }
    52             
    53         }
    54         cout << endl; 
    55     }
    56 }
    57 
    58 ///////////////////////////////////////////////////////////////////////
    59 template <class T>
    60 void PostOrder(BTree<T> *root){
    61     if(root != NULL){
    62         Stack<BTree<T> > stack;
    63         BTree<T> *ptr = root;
    64         BTree<T> *temp;
    65         bool flags;
    66         
    67         do{
    68             while(ptr != NULL){
    69                 stack.push(ptr);
    70                 ptr = ptr->left;
    71             }
    72             
    73             temp = NULL;
    74             flags = true;
    75             
    76             while(flags && !stack.isEmpty()){
    77                 ptr = stack.peek();
    78                 if(ptr->right == temp){
    79                     cout << ptr->data << " ";
    80                     stack.pop();
    81                     temp = ptr;
    82                 }else{
    83                     ptr = ptr->right;
    84                     flags = false;
    85                 }
    86             }
    87         }while(!stack.isEmpty());
    88         cout << endl;        
    89     }
    90 }

    再次引用(程序员基本功之遍历二叉树)中分析。

    后序遍历要稍微复杂一点点,在前序和中序遍历的程序中,当我们准备进入根结点的右子树时,根结点就被扔出栈外了。但在后序遍历时,我们仍需保留它,直到右子树处理完毕。实际上当左子树遍历完成、或者右子树遍历完成时,我们都会在栈里看到根结点,为了区分这两种状态,添加一个临时变量记录前一次访问的结点,如果前一个结点是根结点的右子树,就说明左右子树全都遍历完成了。这也是以上PostOrder采用的方式。


    看到程序员基本功之遍历二叉树中介绍二叉树的层序遍历,搜集一下,以备参考

    非递归的时候,层序遍历使用的是队列,而非栈。处理过程非常简明,遇到一个结点,打印信息,然后依次将左、右子结点加入队列等待后续处理。

     1 from collections import deque
     2 
     3 def VisitTree_LevelOrder(root):
     4   if not root: return
     5   q = deque([root])
     6   while q:
     7     root = q.popleft()
     8     print(root.data)
     9     if root.left: q.append(root.left)
    10     if root.right: q.append(root.right)

    这篇博文(数据结构(六)——二叉树 前序、中序、后序、层次遍历及非递归实现 查找、统计个数、比较、求深度的递归实现)给出了层序遍历的实现代码,如下

    首先是自定义队列

     1 #define MAX 1000  
     2   
     3 typedef struct seqqueue{  
     4     bintree data[MAX];  
     5     int front;  
     6     int rear;  
     7 }seqqueue;  
     8   
     9   
    10 void enter(seqqueue *q,bintree t){  
    11     if(q->rear == MAX){  
    12         printf("the queue is full!
    ");  
    13     }else{  
    14         q->data[q->rear] = t;  
    15         q->rear++;  
    16     }  
    17 }  
    18   
    19 bintree del(seqqueue *q){  
    20     if(q->front == q->rear){  
    21         return NULL;  
    22     }else{  
    23         q->front++;  
    24         return q->data[q->front-1];  
    25     }  
    26 }  

    然后是层序遍历,和上面提到的层序遍历一个道理

     1 void level_tree(bintree t){  
     2     seqqueue q;  
     3     bintree temp;  
     4     q.front = q.rear = 0;  
     5     if(!t){  
     6         printf("the tree is empty
    ");  
     7         return ;  
     8     }  
     9     enter(&q,t);  
    10     while(q.front != q.rear){  
    11         t=del(&q);  
    12         printf("%c ",t->data);  
    13         if(t->lchild){  
    14             enter(&q,t->lchild);  
    15         }  
    16         if(t->rchild){  
    17             enter(&q,t->rchild);  
    18         }  
    19     }  
    20 }  

    还提到二叉树的其他常用算法,一并拿过来

    统计结点个数

    1 int count_tree(bintree t){  
    2     if(t){  
    3         return (count_tree(t->lchild)+count_tree(t->rchild)+1);  
    4     }  
    5     return 0;  
    6 }

    比较两个树是否相同

     1 int is_equal(bintree t1,bintree t2){  
     2     if(!t1 && !t2){      //都为空就相等  
     3         return 1;  
     4     }  
     5     if(t1 && t2 && t1->data == t2->data){      //有一个为空或数据不同就不判断了  
     6         if(is_equal(t1->lchild,t2->lchild))  
     7             if(is_equal(t1->rchild,t2->rchild)){  
     8                 return 1;  
     9             }  
    10     }  
    11     return 0;  
    12 }  

    求二叉树的深度

     1 int hight_tree(bintree t){  
     2     int h,left,right;  
     3     if(!t){  
     4         return 0;  
     5     }  
     6     left = hight_tree(t->lchild);  
     7     right = hight_tree(t->rchild);  
     8     h = (left>right?left:right)+1;  
     9     return h;  
    10 }

    参考博文:

    1.程序员基本功之遍历二叉树

    2.二叉树的非递归前序、中序以及后序遍历C++模版类实现

    3.数据结构(六)——二叉树 前序、中序、后序、层次遍历及非递归实现 查找、统计个数、比较、求深度的递归实现

    作者:RonaldHan
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    SSM整合
    SpringMVC学习笔记
    Spring笔记
    Spring之AOP在XML中的配置方法
    Spring之AOP的注解配置
    Mybatis学习笔记
    css学习笔记
    DOM技术
    Javascript学习笔记
    Hive导出复杂数据到csv文件
  • 原文地址:https://www.cnblogs.com/ronaldhan/p/3303640.html
Copyright © 2020-2023  润新知