數據結構之樹

線索二叉樹

/**
 * 線索二叉樹:普通二叉樹的遍歷操做,須要用到棧來實現遞歸操做,而線索二叉樹,由於其保存了前驅和後繼,在遍歷操做中不需
 * 要使用棧來遞歸,直接根據後繼一直遍歷,直到回到初始頭結點,對比普通二叉樹避免了頻繁的入棧出棧操做,故在時間和空間上
 * 都比較節省
 * @author HP
 *
 */
public class ListOfBiTree {
    
    class node{
        
        int data;
        int leftTag;  // 若爲 0, leftChild 保存左子樹,若爲 1, leftChild 保存前驅
        int rightTag; // 若爲 0, rightChild 保存右子樹,若爲 1, righrChild 保存後繼
        node leftChild;
        node rightChild;
    }
    
    node lastNode = new node();
    
    public void traval(node ListTree) {
        if (ListTree != null) {
            node root = ListTree.leftChild;
            // 遍歷結束時回到頭結點
            while (root != ListTree) {
                // 找到最左邊的節點
                while (root.leftTag == 0) {
                    root = root.leftChild;
                }
                System.out.print(root.data);
                // 利用找到的起始節點開始根據後繼遍歷
                while (root.rightTag == 1 && root.rightChild != ListTree) {
                    root = root.rightChild;
                    System.out.print(root.data);
                }
                
                root = root.rightChild;
            }
        }
    }
    
    // 創建線索二叉樹,tree的初始化只需像普通二叉樹創建便可(tag初始化爲0),在此省略tree的初始化代碼
    public node creatListOfBiTee(node tree, node head) {
        
        if (tree != null && head != null) {
            
            head.leftChild = tree;
            lastNode = head; // 上一次遍歷的節點初始化爲頭結點
            InitTree(tree);
            
            /*
             * 最後一個節點的後繼指回頭結點(其實最後一個節點是沒有後繼節點的,爲了知足線索二叉樹定義及方便遍歷
             * 故指回了頭結點)
             */
            lastNode.rightChild = head;
            lastNode.rightTag = 1;
            /*
             *  線索二叉樹初始化完,改變頭結點的後繼指向根節點(初始化的時候爲了統一操做,是把頭結點的後繼指向了
             *  最左邊的節點)
             */
            head.rightChild = tree;
        }
        
        return head;
    }
    
    public void InitTree(node root) {
        
        if (root != null) {
            
            InitTree(root.leftChild);  // 遞歸對左子樹進行初始化
            
            
            if (root.leftChild == null) {
                // 左子樹爲 null,說明已到葉子節點,將該葉子節點的前驅指向 上一次遍歷到的節點
                root.leftTag = 1;
                root.leftChild = lastNode;
            }else {
                root.leftTag = 0; // 0 表明該節點有左子樹
            }
            
            // 因爲咱們沒法預知當前節點的後繼(由於還沒遍歷到),但咱們知道上一個節點的後繼就是當前節點
            if (lastNode.rightChild == null) {
                lastNode.rightTag = 1;
                lastNode.rightChild = root;
            }else {
                lastNode.rightTag = 0;
            }
            // 當前節點的 左右孩子域更新完,因此當前節點在接下來的操做就是做爲上一次操做的節點了
            lastNode = root;
            
            InitTree(root.rightChild); // 遞歸遍歷右子樹
            
        }
    }
}
View Code

哈夫曼樹

  數據結構類型如圖node

  哈夫曼樹的創建仍是比較容易的,每次取權最小的兩個根節點構成一棵二叉樹,新生成的根加入根節點集合並刪除取出的兩個根節點,修改這兩個節點的雙親域。由於一開始都是n個度爲0的根節點,因此若是造成哈夫曼樹節點數就爲 2n-1 (由二叉樹性質n0 = n2 + 1,哈夫曼樹是由度爲0或2的節點組成的 n + (n-1) = 2n - 1),而後就能夠開 2n-1的數組來存這些節點,前n個元素存原始n個節點,後n-1個存每次生成的結果(固然也能夠用兩條鏈表來操做,一條是原始鏈,一條結果鏈)。具體代碼就不上了。哈夫曼樹通常用在編碼,在獲得哈夫曼樹後怎麼編碼?對,每一個原始根節點進行遍歷,若是是雙親的左孩子,把0壓棧,右孩子把1壓棧,直到雙親域爲空,而後彈棧得出的結果即爲編碼。數組

二叉搜索樹

  它或者是一棵空樹,或者是具備下列性質的二叉樹: 若它的左子樹不空,則左子樹上全部結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉排序(搜索)樹,以下圖:數據結構

  建樹過程就是每次進行節點插入的時候先和根節點比較,小於根節點進入左子樹,若是左子樹爲null則直接插入,不然進入左子樹作遞歸;大於則進入右子樹,若是右子樹爲null則直接插入,不然進入右子樹作遞歸。ide

  貼一道題目編碼

  輸入一個整數數組,判斷該數組是否是某二叉搜索樹的後序遍歷的結果。若是是則輸出Yes,不然輸出No。假設輸入的數組的任意 兩個數字都互不相同。spa

  

public boolean VerifySquenceOfBST(int[] sequence) {
        int n = sequence.length;
        if (n == 0) {
            return false;
        }
        if (n == 1 || n == 2) {
            return true;
        }
        if (is(sequence, 0, sequence.length - 1)) {
            return true;
        }
        return false;
    }

    public boolean is(int[] back, int start, int end) {
        
        if (end <= start) {
            // 遍歷到尾只剩一個元素
            return true;
        }
        
        int i = start;
        /* 
         * 由於後續遍歷的最後一個元素必定是根節點,又由於是二叉搜索樹,前面的元素必定是左子樹和右子樹,左子樹的所
         * 有節點必定小於根節點,右子樹的全部節點必定大於根節點,經過如下循環找出左右子樹分割點
         */
        for (; i < end; i++) {
            if (back[i] > back[end]) {
                break;
            }
        }
        for (int j = i; j < end; j++) {
            // 若是是後續遍歷的結果,從 j 開始的後續節點爲右子樹節點,全部節點值要大於根,不然說明並非後續遍
            // 歷結果
            if (back[j] < back[end]) {
                return false;
            }
        }
        
        return is(back, 0, i - 1) && is(back, i, end - 1);
    }
View Code
相關文章
相關標籤/搜索