Android版數據結構與算法(六):樹與二叉樹


版權聲明:本文出自汪磊的博客,未經作者允許禁止轉載。

 之前的篇章主要講解了數據結構中的線性結構,所謂線性結構就是數據與數據之間是一對一的關系,接下來我們就要進入非線性結構的世界了,主要是樹與圖,好了接下來我們將會了解到樹以及二叉樹,二叉平衡樹,赫夫曼樹等原理以及java代碼的實現,先從最基礎的開始學習吧。

一、樹

樹的定義:

樹是n(n>=0)個結點的有限集合。

當n=0時,集合為空,稱為空樹。

在任意一顆非空樹中,有且僅有一個特定的結點稱為根。

當n>1時,除根結點以外的其余結點可分成m(m>=0)個不相交的有限結點集合T1,T2….Tm.其中每個集合本身也是一棵樹,稱為根的子樹。

如下圖就是一棵樹:

可以看到,樹這種數據結構數據之間是一對一或者一對多關系,不再是一對一的關系

在上圖中節點A叫做整棵樹的根節點,一棵樹中只有一個根節點。

根節點可以生出多個孩子節點,孩子節點又可以生出多個孩子節點。比如A的孩子節點為B和C,D的孩子節點為G,H,I。

每個孩子節點只有一個父節點,比如D的父節點為B,E的父節點為C。

好了,關於樹的定義介紹到這,很簡單。

二、樹的相關術語

 

節點的度

節點含有的子樹個數,叫做節點的度。度為0的節點成為葉子結點或終端結點。比如上圖中D的度為3,E的度為1.

G,H,I,J的度為0,叫做葉子結點。

樹的度

 一棵樹中 最大節點的度樹的度。比如上圖中樹的度為3

結點的層次

從根結點算起,為第一層,其余依次類推如上圖。B,C的層次為2,G,H的層次為4。

樹中節點的最大層次稱為樹的高度或深度。上圖中樹的高度或深度為4

三、樹的存儲結構

簡單的順序存儲不能滿足樹的實現,需要結合順序存儲和鏈式存儲來解決。

樹的存儲方式主要有三種:

雙親表示法:每個節點不僅保存自己數據還附帶一個指示器指示其父節點的角標,這種方式可以用數組來存儲。

如圖:

這種存儲方式特點是:查找一個節點的孩子節點會很麻煩但是查找其父節點很簡單。

孩子表示法:每個節點不僅保存自己數據信息還附帶指示其孩子的指示器,這種方式用鏈表來存儲比較合適。

如圖:

這種存儲方式特點是:查找一個節點的父親節點會很麻煩但是查找其孩子節點很簡單。

理想表示法:數組+鏈表的存儲方式,把每個結點的孩子結點排列起來,以單鏈表方式連接起來,則n個孩子有n個孩子鏈表,如果是葉子結點則此鏈表為空,然后n個頭指針又組成線性表,采用順序存儲方式,存儲在一個一維數組中。

如圖:

這種方式查找父節點與孩子結點都比較簡便。

以上主要介紹了樹的一些概念以及存儲方式介紹,實際我們用的更多的是二叉樹,接下來我們看下二叉樹。

四、二叉樹的概念

二叉樹定義:二叉樹是n(n>=0)個結點的有限集合,該集合或者為空,或者由一個根結點和兩課互不相交的,分別稱為根結點左子樹和右子樹的二叉樹組成。

用人話說,二叉樹是每個節點至多有兩個子樹的樹。

如圖就是一顆二叉樹:

 

 

五、特殊二叉樹

斜樹:所有結點只有左子樹的二叉樹叫做左斜樹,所有結點只有右子樹的二叉樹叫做右斜樹。

如圖:

滿二叉樹:在一棵二叉樹中,所有分支結點都有左子樹與右子樹,並且所有葉子結點都在同一層則為滿二叉樹。

如圖:

完全二叉樹:所有葉子節點都出現在 k 或者 k-1 層,而且從 1 到 k-1 層必須達到最大節點數,第 k 層可是不是慢的,但是第 k 層的所有節點必須集中在最左邊。

如圖:

 

 六、二叉樹的遍歷

二叉樹的遍歷主要有三種:先序遍歷,中序遍歷,后續遍歷,接下來我們挨個了解一下。

先序遍歷:先訪問根結點,再先序遍歷左子樹,再先序遍歷右子樹。

如圖所示:

 

先序遍歷結果為:ABDGHCEIF

中序遍歷:先中序遍歷左子樹,再訪問根結點,再中序遍歷右子樹。

如圖:

中序遍歷結果為:GDHBAEICF

后序遍歷:先后序遍歷左子樹,再后序遍歷右子樹,再訪問根結點。

如圖:

后序遍歷結果:GHDBIEFCA

七、java實現二叉樹

先來看看每個結點類:

 1     public class TreeNode{
 2         private String data;//自己結點數據
 3         private TreeNode leftChild;//左孩子
 4         private TreeNode rightChild;//右孩子
 5         
 6         public String getData() {
 7             return data;
 8         }
 9         
10         public void setData(String data) {
11             this.data = data;
12         }
13         
14         public TreeNode(String data){
15             this.data = data;
16             this.leftChild = null;
17             this.rightChild = null;
18         }
19     }

很簡單,每個結點信息包含自己結點數據以及指向左右孩子的指針(為了方便,我這里就叫指針了)。

二叉樹的創建

我們創建如下二叉樹:

代碼實現:

public class BinaryTree {
    private TreeNode  root = null;

    public TreeNode getRoot() {
        return root;
    }

    public BinaryTree(){
        root = new TreeNode("A");
    }
    
    /**
     * 構建二叉樹
     *          A
     *     B        C
     *  D    E    F   G
     */
    public void createBinaryTree(){
        TreeNode nodeB = new TreeNode("B");
        TreeNode nodeC = new TreeNode("C");
        TreeNode nodeD = new TreeNode("D");
        TreeNode nodeE = new TreeNode("E");
        TreeNode nodeF = new TreeNode("F");
        TreeNode nodeG = new TreeNode("G");
        root.leftChild = nodeB;
        root.rightChild = nodeC;
        nodeB.leftChild = nodeD;
        nodeB.rightChild = nodeE;
        nodeC.leftChild = nodeF;
        nodeC.rightChild = nodeG;
    }
        。。。。。。。
}

創建BinaryTree的時候就已經創建根結點A,createBinaryTree()方法中創建其余結點並且建立相應關系。

獲得二叉樹的高度

樹中節點的最大層次稱為樹的高度,因此獲得樹的高度需要遞歸獲取所有節點的高度,取最大值。

     /**
     * 求二叉樹的高度
     * @author Administrator
     *
     */
    public int getHeight(){
        return getHeight(root);
    }
    
    private int getHeight(TreeNode node) {
        if(node == null){
            return 0;
        }else{
            int i = getHeight(node.leftChild);
            int j = getHeight(node.rightChild);
            return (i<j)?j+1:i+1;
        }
    }        

獲取二叉樹的結點數

獲取二叉樹結點總數,需要遍歷左右子樹然后相加

 1     /**
 2      * 獲取二叉樹的結點數
 3      * @author Administrator
 4      *
 5      */
 6     public int getSize(){
 7         return getSize(root);
 8     }
 9     
10     private int getSize(TreeNode node) {
11         if(node == null){
12             return 0;
13         }else{
14             return 1+getSize(node.leftChild)+getSize(node.rightChild);
15         }
16     }

二叉樹的遍歷

二叉樹遍歷分為前序遍歷,中序遍歷,后續遍歷,主要也是遞歸思想,下面直接給出代碼

    /**
     * 前序遍歷——迭代
     * @author Administrator
     *
     */
    public void preOrder(TreeNode node){
        if(node == null){
            return;
        }else{
            System.out.println("preOrder data:"+node.getData());
            preOrder(node.leftChild);
            preOrder(node.rightChild);
        }
    }

    /**
     * 中序遍歷——迭代
     * @author Administrator
     *
     */
    public void midOrder(TreeNode node){
        if(node == null){
            return;
        }else{
            midOrder(node.leftChild);
            System.out.println("midOrder data:"+node.getData());
            midOrder(node.rightChild);
        }
    }
    
    /**
     * 后序遍歷——迭代
     * @author Administrator
     *
     */
    public void postOrder(TreeNode node){
        if(node == null){
            return;
        }else{
            postOrder(node.leftChild);
            postOrder(node.rightChild);
            System.out.println("postOrder data:"+node.getData());
        }
    }

獲取某一結點的父結點

獲取結點的父節點也是遞歸思想,先判斷當前節點左右孩子是否與給定節點信息相等,相等則當前結點即為給定結點的父節點,否則繼續遞歸左子樹,右子樹。

 1 /**
 2      * 查找某一結點的父結點
 3      * @param data
 4      * @return
 5      */
 6     public TreeNode getParent(String data){
 7         //封裝為內部結點信息
 8         TreeNode node = new TreeNode(data);
 9         //
10         if (root == null || node.data.equals(root.data)){
11             //根結點為null或者要查找的結點就為根結點,則直接返回null,根結點沒有父結點
12             return null;
13         }
14         return getParent(root, node);//遞歸查找
15     }
16 
17     public TreeNode getParent(TreeNode subTree, TreeNode node) {
18 
19         if (null == subTree){//子樹為null,直接返回null
20             return null;
21         }
22         //判斷左或者右結點是否與給定結點相等,相等則此結點即為給定結點的父結點
23         if(subTree.leftChild.data.equals(node.data) || subTree.rightChild.data.equals(node.data)){
24             return subTree;
25         }
26         //以上都不符合,則遞歸查找
27         if (getParent(subTree.leftChild,node)!=null){//先查找左子樹,左子樹找不到查詢右子樹
28             return getParent(subTree.leftChild,node);
29         }else {
30             return getParent(subTree.rightChild,node);
31         }
32     }

八、總結

以上總結了樹與二叉樹的一些概念,重點就是二叉樹的遍歷以及java代碼實現,比較簡單,沒什么多余解釋,下一篇了解一下赫夫曼樹以及二叉排序樹。

聲明:文章將會陸續搬遷到個人公眾號,以后文章也會第一時間發布到個人公眾號,及時獲取文章內容請關注公眾號

 


免責聲明!

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



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