/** * 線索二叉樹:普通二叉樹的遍歷操做,須要用到棧來實現遞歸操做,而線索二叉樹,由於其保存了前驅和後繼,在遍歷操做中不需 * 要使用棧來遞歸,直接根據後繼一直遍歷,直到回到初始頭結點,對比普通二叉樹避免了頻繁的入棧出棧操做,故在時間和空間上 * 都比較節省 * @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); // 遞歸遍歷右子樹 } } }
數據結構類型如圖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); }