1. 程式人生 > 其它 >前驅線索樹的遍歷(Java個人理解)

前驅線索樹的遍歷(Java個人理解)

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 + '\'' +
                '}';
    }

}