線索化二叉樹詳解


線索化二叉樹詳解

說明

  1. 線索化二叉樹,由字面意思,就是將二叉樹的節點拿線索連接起來
  2. 實質上,也就是將二叉樹的葉子節點左右指針域彼此連接一個節點
  3. 二叉樹的非葉子節點的左右指針域都各自連接了一個節點,但是葉子節點的左右指針域是空的,因此考慮將葉子節點的左右指針域按照某種遍歷次序連接起來
  4. 按照二叉樹的遍歷方式,有前序中序后續三種遍歷方式,因此可以形成三種鏈式結構
  5. 每個葉子節點前一個節點稱為前驅節點,后一個節點稱為后繼節點,如果當前節點沒有前驅或者后繼節點,則直接置為空
  6. 以中序線索化二叉樹為例,編寫中序線索化二叉樹的方法
  7. 先判斷當前節點是否為空,如果為空,則直接返回
  8. 否則先向左遞歸線索化二叉樹的左子樹
  9. 然后再線索化當前節點,定義屬性pre保存當前節點的前一個節點,因此當前節點的前一個節點置為pre
  10. 注意當前節點的后一個節點,需要用pre保存當前節點,然后遍歷到后一個節點,然后用pre指向
  11. 注意第一個節點和最后一個節點
  12. 中序線索化如下,前序和后續類似

源碼及分析

節點類
//創建節點
class HeroNode{
    //編號
    private int no;
    //姓名
    private String name;
    //左子樹
    private HeroNode left;
    //右子樹
    private HeroNode right;

    //線索化的前驅節點類型,是節點還是樹,假定 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 HeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
    //刪除節點

    /**
     *
     * @param no 要刪除的節點編號
     */
    public void delNode(int no){
        //判斷當前節點的左子樹是否為空,如果不為空,再判斷是否為要刪除的節點
        if (this.left != null && this.left.no == no){
            this.left = null;
        }
        //判斷當前節點的右子樹是否為空,如果不為空,再判斷是否為要刪除的節點
        if (this.right != null && this.right.no == no){
            this.right = null;
        }
        //否則向左向右遞歸
        if (this.left != null){
            this.left.delNode(no);
        }
        if (this.right != null){
            this.right.delNode(no);
        }
    }


    //前序中序后序遍歷主要區別在於父節點的輸出位置不同,
    /**
     * 前序遍歷先輸出父節點信息,然后判斷左子樹是否為空,如果不為空,則遞歸前序遍歷
     * 然后再判斷右子樹是否為空,如果不為空,則遞歸遍歷前序遍歷
     */
    //前序遍歷
    public void preOrder(){
        //先輸入當前節點信息
        System.out.println(this);
        //然后判斷當前節點的左子樹是否為空
        if (this.left != null){
            this.left.preOrder();
        }
        //再判斷當前節點的右子樹是否為空
        if (this.right != null){
            this.right.preOrder();
        }

    }
    //中序遍歷
    public void infixOrder(){
        //先判斷當前節點的左子樹是否為空
        if (this.left != null){
            this.left.infixOrder();
        }
        //再輸出當前節點的信息
        System.out.println(this);
        //然后再判斷當前節點的右子樹是否為空
        if (this.right != null){
            this.right.infixOrder();
        }
    }
    //后序遍歷
    public void postOrder(){
        //先判斷當前節點的左子樹是否為空
        if (this.left != null){
            this.left.postOrder();
        }
        //再判斷當前節點的右子樹是否為空
        if (this.right != null){
            this.right.postOrder();
        }
        //最后輸出當前節點的信息
        System.out.println(this);
    }

    //前序查找

    /**
     * 前序遍歷查找
     * @param no 要查找的節點編號
     * @return 返回查找的結果
     */
    public HeroNode preOrderSearch(int no){
        //先判斷當前節點是不是要查找的節點
        if (this.no == no){
            return this;
        }
        //如果當前節點不是要查找的節點,則判斷左子樹是否為空,若不為空,則遞歸前序查找
        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.preOrderSearch(no);
        }
        //如果在左子樹找到,則直接返回
        if (resNode != null){
            return resNode;
        }
        //如果左子樹也沒有找到,則判斷右子樹是否為空,並遞歸
        if (this.right != null){
            resNode = this.right.preOrderSearch(no);
        }
        return resNode;
    }
    //中序查找

    /**
     * 中序遍歷查找
     * @param no 要查找的節點編號
     * @return 返回查找的結果
     */
    public HeroNode infixOrderSearch(int no){
        //先判斷當前節點左子樹是否為空,如果不為空則遞歸中序查找
        //定義變量保存查找的結果
        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.preOrderSearch(no);
        }
        //如果查找到,則直接返回
        if (resNode != null){
            return resNode;
        }
        //如果沒有找到,判斷當前節點是不是要查找的節點
        if (this.no == no){
            return this;
        }
        //如果還沒有找到,則判斷右子樹是否為空,不為空則遞歸中序查找
        if (this.right != null){
            resNode = this.right.infixOrderSearch(no);
        }
        return resNode;
    }
    //后序查找

    /**
     * 后續遍歷查找
     * @param no 要查找的節點編號
     * @return 返回查找的結果
     */
    public HeroNode postOrderSearch(int no){
        //判斷當前節點的左子樹是否為空,如果不為空,則遞歸后續查找
        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.postOrderSearch(no);
        }
        if (resNode != null){
            return resNode;
        }
        if (this.right != null){
            resNode = this.right.postOrderSearch(no);
        }
        if (resNode != null){
            return resNode;
        }
        if (this.no == no){
            return this;
        }
        return resNode;
    }
}

線索化二叉樹類
//創建一顆線索化二叉樹
class ThreaderBinaryTree{
    //二叉樹必有根節點
    private HeroNode root;
    //定義變量指向前驅節點,默認為空
    private HeroNode pre = null;

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    //編寫中序線索化二叉樹的方法
    /**
     *
     * @param node node為當前要中序線索化的節點
     */
    public void infixThreadedBinaryTree(HeroNode node){
        //先判斷當前節點是否為空
        if (node == null){
            return;
        }
        //如果不為空,先線索化左子樹
        infixThreadedBinaryTree(node.getLeft());
        //再線索化當前節點
        //當前節點的前驅節點為pre,后繼節點需要在下一個節點連通,因為是單向的

        //設置當前節點的前驅節點,並設置前驅節點類型
        if (node.getLeft() == null){
            node.setLeft(pre);
            node.setLeftType(1);
        }
        //設置當前節點的后繼節點及其類型
        if (pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setRightType(1);
        }
        //讓pre指向當前節點
        pre = node;
        //最后再線索化右子樹
        infixThreadedBinaryTree(node.getRight());
    }
    //重載線索化的方法
    public void infixThreadedBinaryTree(){
        this.infixThreadedBinaryTree(root);
    }

    //刪除節點
    /**
     *
     * @param no 要刪除的節點編號
     */
    public void delNode(int no){
        //先判斷二叉樹是否為空
        if (this.root != null){
            //再判斷當前root節點是不是要刪除的節點
            if (this.root.getNo() == no){
                root = null;
            }else {
                this.root.delNode(no);
            }
        }else {
            System.out.println("二叉樹為空,不能刪除...");
        }

    }
    //前序遍歷
    public void preOrder(){
        if (this.root != null){
            this.root.preOrder();
        }else {
            System.out.println("二叉樹為空...");
        }
    }
    //中序遍歷
    public void infixOrder(){
        if (this.root != null){
            this.root.infixOrder();
        }else {
            System.out.println("二叉樹為空...");
        }
    }
    //后續遍歷
    public void postOrder(){
        if (this.root != null){
            this.root.postOrder();
        }else {
            System.out.println("二叉樹為空...");
        }
    }
    //前序查找
    public HeroNode preOrderSearch(int no){
        if (this.root != null){
            return this.root.preOrderSearch(no);
        }else {
            return null;
        }
    }
    //中序查找
    public HeroNode infixOrderSearch(int no){
        if (this.root != null){
            return this.root.infixOrderSearch(no);
        }else {
            return null;
        }
    }
    //后續查找
    public HeroNode postOrderSearch(int no){
        if (this.root != null){
            return this.root.postOrderSearch(no);
        }else {
            return null;
        }
    }
}
測試類
public static void main(String[] args) {
        ThreaderBinaryTree threaderBinaryTree = new ThreaderBinaryTree();
        HeroNode root = new HeroNode(1,"tom");
        HeroNode node2 = new HeroNode(3,"jack");
        HeroNode node3 = new HeroNode(6,"smith");
        HeroNode node4 = new HeroNode(8,"king");
        HeroNode node5 = new HeroNode(10,"mary");
        HeroNode node6 = new HeroNode(14,"dop");
        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);
        threaderBinaryTree.setRoot(root);

        //進行線索化
        threaderBinaryTree.infixThreadedBinaryTree();

        //測試線索化的結果
        System.out.println("node5的前一個節點 = " + node5.getLeft());
        System.out.println("node5的后一個節點 = " + node5.getRight());

    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM