前驅線索樹的遍歷(Java個人理解)
阿新 • • 發佈:2021-08-10
13.3.2 遍歷前序線索樹
我的個人理解:所謂的前序遍歷就是每讀到一個節點,就輸出他的值,先左後右,這是一般二叉樹的思路,但是,線索二叉樹,子葉節點可能存在前驅和後繼結點,那麼,我們可以利用這一點,如果當前節點存在後繼節點,我們直接在輸出完當前節點後直接指向後繼結點(按照一點的遞迴思想我們是一步一步返回去,然後再向右查詢,由於存在後繼節點,那麼我們可以直接利用,大大縮短了查詢效率)
package tree.threadedbinarytree; public class ThreadedBinaryTreeDemo { public static void main(String[] args) { // 測試 把中序線索二叉樹 Node1 root = new Node1(1, "12"); Node1 node2 = new Node1(3, "13"); Node1 node3 = new Node1(6, "16"); Node1 node4 = new Node1(8, "18"); Node1 node5 = new Node1(10, "114"); Node1 node6 = new Node1(14, "114"); // 二叉樹後面要遞迴建立,現在手動建立 root.setLeft(node2); root.setRight(node3); node2.setLeft(node4); node2.setRight(node5); node3.setLeft(node6); infixThreadedBinaryTree infixThreadedBinaryTree = new infixThreadedBinaryTree(); // 測試前序線索化 infixThreadedBinaryTree.setRoot(root); infixThreadedBinaryTree.preNodes(); // 測試:以10號結點為測試 Node1 leftNode = node5.getLeft(); Node1 rightNode = node5.getRight(); System.out.println("10號結點的前驅結點時:" + leftNode); System.out.println("10號結點的後繼結點" + rightNode); System.out.println("前序線索樹遍歷"); infixThreadedBinaryTree.preThreadedList(); } } // 線索化二叉樹 實現了線索化功能的二叉樹 class infixThreadedBinaryTree{ private Node1 root; // 為了實現線索化,需要建立要給指向當前節點的前驅結點的指標 // 在遞迴的進行線索時,pre 總是保留一個結點 private Node1 pre = null; // 遍歷中序線索二叉樹 public void infixThreadedList(){ // 定義一個變數,儲存當前遍歷的節點,從root開始 Node1 node = root; while(node != null){ // 迴圈的找到leftType == 1的節點,第一個找到的就是8 // 後面隨著遍歷node會變化, // 因為當leftType == 1時,說明該節點時按照線索化處理後的有效節點 while (node.getLeftType() == 0){ node = node.getLeft(); } // 列印當前節點 System.out.println(node); // 如果當前節點的右指標指向的是後繼結點,就一直輸出 while (node.getRightType() == 1){ // 說明當前節點指向後繼結點 // 獲取當前節點的後繼結點 node = node.getRight(); System.out.println(node); } // 替換這個便利的節點 node = node.getRight(); } } // 遍歷前序線索二叉樹 public void preThreadedList(){ Node1 node = root; System.out.println(node); // 先輸出當前node的值 while (node != null){ // 然後判斷左節點是否是前驅結點,如果不是且不為空,就輸出它的左孩子,並且指標指向左節點,進行下一次迴圈 if (node.getLeftType() == 0 && node.getLeft() != null){ System.out.println(node.getLeft()); node = node.getLeft(); continue; } // 判斷右節點是否是後繼結點,如果不是且為不為空,就輸出它的右孩子,並且指標指向右節點,進行下一次迴圈 if (node.getRightType() == 0 && node.getRight() != null){ System.out.println(node.getRight()); node = node.getRight(); continue; } // 判斷當前節點的右節點是否是後繼結點,如果是,直接輸出它的後繼結點,然後指標指向後繼結點 if (node.getRightType() == 1){ System.out.println(node.getRight()); node = node.getRight(); } } } // 過載一把threadeNodes方法 public void threadeNodes(){ this.threadedNodes(root); } // 編寫二叉樹進行中序線索化的方法 /** * * @param node 就是當前需要線索化的結點 */ public void threadedNodes(Node1 node){ // 如果 node == null,不能進行線索化 if (node == null){ return; } // 1. 先線索化左子樹 threadedNodes(node.getLeft()); // 2. 線索化當前結點 // 2.1 先處理當前節點的前驅結點 if (node.getLeft() == null){ // 讓當前節點的左指標指向前驅結點 node.setLeft(pre); // 修改當前節點的左指標的型別,指向前驅結點 node.setLeftType(1); } // 2.2 處理當前節點的後繼結點 if (pre != null && pre.getRight() == null){ // 讓前驅結點的右指標指向當前結點 pre.setRight(node); // 修改前驅結點的右指標型別 pre.setRightType(1); } // 沒處理一個節點後,讓當前結點時下一個節點的前驅結點 pre = node; // 3. 再線索化右子樹 threadedNodes(node.getRight()); } public void preNodes(){ this.preNodes(root); } // 前序線索化 public void preNodes(Node1 node){ if (node == null){ return; } if (node.getLeft() == null){ node.setLeft(pre); node.setLeftType(1); } if (pre != null && pre.getRight() == null){ pre.setRight(node); pre.setRightType(1); } pre = node; if (node.getLeftType() == 0){ preNodes(node.getLeft()); } if (node.getRightType() == 0){ preNodes(node.getRight()); } } // 後序線索化 public void postNodes(){ this.postNodes(root); } public void postNodes(Node1 node){ if (node == null){ return; } postNodes(node.getLeft()); postNodes(node.getRight()); if (node.getLeft() == null){ node.setLeft(pre); node.setLeftType(1); } if ( pre != null && pre.getRight() == null){ pre.setRight(node); pre.setRightType(1); } pre = node; } public void setRoot(Node1 root) { this.root = root; } } // 先建立節點 class Node1{ private int id; private String name; private Node1 left; private Node1 right; // 說明 // 1. 如果leftType == 0 表示的指向的是左子樹,如果1則表示指向前驅結點 // 2. 如果rightType == 0 表示指向的是右子樹,如果1則表示指向的是後繼結點 private int leftType; private int rightType; public int getLeftType() { return leftType; } public void setLeftType(int leftType) { this.leftType = leftType; } public int getRightType() { return rightType; } public void setRightType(int rightType) { this.rightType = rightType; } public Node1(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Node1 getLeft() { return left; } public void setLeft(Node1 left) { this.left = left; } public Node1 getRight() { return right; } public void setRight(Node1 right) { this.right = right; } @Override public String toString() { return "Node1{" + "id=" + id + ", name='" + name + '\'' + '}'; } }