morris算法-----高級二叉樹遍歷算法


  

  在遍歷兒叉樹時,常常使用的是遞歸遍歷,或者是借助於棧來迭代,在遍歷過程中,每個節點僅訪問一次,所以這樣遍歷的時間復雜度為O(n),空間復雜度為O(n),並且遞歸的算法易於理解和實現。在遍歷過程中,遞歸遍歷過程的空間復雜度卻是O(n),就算是轉換為使用棧空間迭代時間,還是沒有改變算法對額外空間的需求,在學習數據結構課程時,還學習了線索二叉樹,在線索二叉樹中,使用線索來保存節點的前驅和后繼的信息,而這些線索是利用了葉節點的空指針域來保存,所以知道了樹種每個節點的前驅和后繼的位置(指針)可以有效降低遍歷過程中對空間的需求,但是使用線索二叉樹必須先通過一次二叉樹遍歷算法,為二叉樹建立線索,此外還需要標記每個節點的指針域是線索還是指針,使每個結點都有了唯一前驅和后繼(第一個結點無前驅,最后一個結點無后繼)。對於二叉樹的一個結點,查找其左右子女是方便的,其前驅后繼只有在遍歷中得到。為了容易找到前驅和后繼,有兩種方法。一是在結點結構中增加向前和向后的指針fwd和bkd,這種方法增加了存儲開銷,不可取;二是利用二叉樹的空鏈指針。現將二叉樹的結點結構重新定義如下:

lchild
ltag
data
rtag
rchild
其中:ltag=0 時lchild指向左子女;
ltag=1 時lchild指向前驅;
rtag=0 時rchild指向右子女;
rtag=1 時rchild指向后繼;

下面來看看Morris二叉樹遍歷算法。 

  Morris算法與遞歸和使用棧空間遍歷的思想不同,它使用二叉樹中的葉節點的right指針來保存后面將要訪問的節點的信息,當這個right指針使用完成之后,再將它置為NULL,但是在訪問過程中有些節點會訪問兩次,所以與遞歸的空間換時間的思路不同,Morris則是使用時間換空間的思想,這里講的很簡單,大體意思每次去找當前節點的左子樹的最右子節點,最右子節點的右節點指向當前根節點,然后以左子樹為根節點,再找其左子樹的最右子節點,最右子節點再指向當前的根節點。這是我自己的理解,以中序遍歷為例。下面是代碼實現:

 

public static void morrisIn(Node head){
    if (head==null){
        return;
    } 
      Node cur1=head;
      Node cur2=null;
      while(cur1 !=null){
         cur2=cur1.left;
         if(cur2!=null){
            while (cur2.right !=null && cur2.right!=cur1){
            cur2=cur2.right;
           }
           if(cur2.right ==null ){
           cur2.right =cur1;
           cur1 = cur1.left;
            continue;
          }else {
                cur2,right=null;  
          }
      }
      Sysetem.out.print(cur1.value+" "); 
      cur1=cur1.right;     
    }
     System.out.println();  
}    

前序遍歷就是第一次訪問的該節點是就答應該節點,代碼示例略。

后序遍歷比較復雜,即在訪問該節點的左子樹的最右子節點時,最右子節點的子節點之前為空,由於現在指向着該節點,即打印時機為第二次訪問到一個根節點是,倒序打印該根節點的左子樹的整個最右子樹。程序差不都,掌握打印時機即可。(再加一個倒序打印左子樹的整個最右子樹函數即可),代碼貼圖如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM