第十二講 數據結構之樹

樹的定義

樹(Tree)是n(n≥0)個結點的有限集T,并且當n>0時滿足下列條件:
1.有且僅有一個特定的稱為根(Root)的結點;
2.當n>1時,其余結點可以劃分為m(m>0)個互不相交的有限集T1、T2 、…、Tm,每個集Ti(1≤i≤m)均為樹,且稱為樹T的子樹(SubTree)。
不含任何結點(即n=0)的樹,稱為空樹。
如下圖就是一棵樹的結構:


樹的基本術語

結點:存儲數據元素和指向子樹的鏈接,由數據元素和構造數據元素之間關系的引用組成。
孩子結點:樹中一個結點的子樹的根結點稱為這個結點的孩子結點,如上圖中的A的孩子結點有B、C、D
雙親結點:樹中某個結點有孩子結點(即該結點的度不為0),該結點稱為它孩子結點的雙親結點,也叫前驅結點。雙親結點和孩子結點是相互的,如上圖中,A的孩子結點是B、C、D,B、C、D的雙親結點是A。
兄弟結點:具有相同雙親結點(即同一個前驅)的結點稱為兄弟結點,如上圖中B、B、D為兄弟結點。
結點的度:結點所有子樹的個數稱為該結點的度,如上圖,A的度為3,B的度為2.
樹的度:樹中所有結點的度的最大值稱為樹的度,如上圖的度為3.
葉子結點:度為0的結點稱為葉子結點,也叫終端結點。如上圖的K、L、F、G、M、I、J
分支結點:度不為0的結點稱為分支結點,也叫非終端結點。如上圖的A、B、C、D、E、H
結點的層次:從根結點到樹中某結點所經路徑的分支數稱為該結點的層次。根結點的層次一般為1(也可以自己定義為0),這樣,其它結點的層次是其雙親結點的層次加1.
樹的深度:樹中所有結點的層次的最大值稱為該樹的深度(也就是最下面那個結點的層次)。
有序樹和無序樹:樹中任意一個結點的各子樹按從左到右是有序的,稱為有序樹,否則稱為無序樹。

樹的抽象數據類型描述

ADT 樹(Tree)
Data
具有相同特性的數據元素的集合;樹中數據元素間的結構關系由樹的定義確定。
Operation
(1)initTree(T):創建1個空樹T
(2)destroyTree(T):銷毀樹
(3)creatTree(T,deinition):構造樹
(4)clearTree(T):置空樹,將樹T置為空樹
(5)treeEmpty(T):判空樹
(6)treeDepth(T):求樹的深度
(7)root(T):獲得樹根
(8)value(T,cur_e,e):獲取結點,將樹中結點cur_e存入e單元中。
(9)assign(T,cur_e,value):數據賦值,將結點value,賦值于樹T的結點cur_e中。
(10)parent(T,cur_e):獲得雙親, 返回樹T中結點cur_e的雙親結點。
(11)leftChild(T,cur_e):獲得最左孩子,返回樹T中結點cur_e的最左孩子。
(12)rightSibling(T,cur_e):獲得右兄弟,返回樹T中結點cur_e的右兄弟。
(13)InsertChild(T,p,i,c):插入子樹,將樹c插入到樹T中p指向結點的第i個子樹之前。
(14)deleteChild(T,p,i):刪除子樹, 刪除樹T中p指向結點的第i個子樹。
(15)traverseTree(T,visit()):遍歷樹
endADT

樹的實現

樹是一種遞歸結構,表示方式一般有孩子兄弟表示法和孩子表示法兩種。樹實現方式有很多種、有可以由廣義表的遞歸實現,也可以有二叉樹實現,其中最常見的是將樹用孩子兄弟表示法轉化成二叉樹來實現,如下圖:


/**
 * 以孩子表示法為例講一下樹的實現
 * @author wangxiaojian
 */
public class Tree {
    private Object data;
    private List<Tree> childs;

    public Tree() {
        data = null;
        childs = new ArrayList<>();
    }

    public Tree(Object data) {
        this.data = data;
        childs = new ArrayList<>();
    }

    /**
     * 添加子樹
     *
     * @param tree 子樹
     */
    public void addNode(Tree tree) {
        childs.add(tree);
    }

    /**
     * 置空樹
     */
    public void clearTree() {
        data = null;
        childs.clear();
    }

    /**
     * 求樹的深度
     *
     * @return 樹的深度
     */
    public int dept() {
        return dept(this);
    }

    /**
     * 求樹的深度
     *
     * @param tree
     * @return
     */
    private int dept(Tree tree) {
        if (tree.isEmpty()) {
            return 0;
        } else if (tree.isLeaf()) {
            return 1;
        } else {
            int n = childs.size();
            int[] a = new int[n];
            for (int i = 0; i < n; i++) {
                if (childs.get(i).isEmpty()) {
                    a[i] = 0 + 1;
                } else {
                    a[i] = dept(childs.get(i)) + 1;
                }
            }
            Arrays.sort(a);
            return a[n - 1];
        }
    }

    /**
     * 返回遞i個子樹
     *
     * @param i
     * @return
     */
    public Tree getChild(int i) {
        return childs.get(i);
    }

    /**
     * 求第一個孩子 結點
     *
     * @return
     */
    public Tree getFirstChild() {
        return childs.get(0);

    }

    /**
     * 求最后 一個孩子結點
     *
     * @return
     */
    public Tree getLastChild() {
        return childs.get(childs.size() - 1);
    }

    public List<Tree> getChilds() {
        return childs;
    }

    /**
     * 獲得根結點的數據
     *
     * @return
     */
    public Object getRootData() {
        return data;
    }

    /**
     * 判斷是否為空樹
     *
     * @return 如果為空,返回true,否則返回false
     */
    public boolean isEmpty() {
        if (childs.isEmpty() && data == null) {
            return true;
        }
        return false;
    }

    /**
     * 判斷是否為葉子結點
     *
     * @return
     */
    public boolean isLeaf() {
        if (childs.isEmpty()) {
            return true;
        }
        return false;
    }

    /**
     * 獲得樹根
     *
     * @return 樹的根
     */
    public Tree root() {
        return this;
    }

    /**
     * 設置根結點的數據
     */
    public void setRootData(Object data) {
        this.data = data;
    }

    /**
     * 求結點數
     *
     * @return 結點的個數
     */
    public int size() {
        return size(this);
    }

    /**
     * 求結點數
     *
     * @param tree
     * @return
     */
    private int size(Tree tree) {
        if (tree.isEmpty()) {
            return 0;
        } else if (tree.isLeaf()) {
            return 1;
        } else {
            int count = 1;
            int n = childs.size();
            for(int i=0; i<n; i++) {
                if(!childs.get(i).isEmpty()) {
                    count += size(childs.get(i));
                }
            }
            return count;
        }
    }

}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。