07.Java數據結構與算法之~二叉樹的查找與刪除

07.Java數據結構與算法之~二叉樹的查找與刪除

本文是上一篇文章的後續,詳情請點擊該鏈接

二叉樹-查找指定結點

使用前序,中序,後序的方式來查詢指定的結點

前序查找思路:

       1.先判斷當前結點是否等於要查找的,如果是相等,則返回當前結點

       2.如果不等,則判斷當前結點的左子結點是否爲空,如果不爲空,則遞歸前序查找

       3.如果左遞歸前序查找,找到結點,則返回。否則繼續判斷當前結點的右子結點是否爲空,如果不空,則繼續向右遞歸前序

中序查找思路:

       1.判斷當前結點的左子結點是否爲空,如果不爲空,則遞歸中序查找

       2.如果找到則返回,如果沒找到,就和當前結點比較,如果是則返回當前結點,否則繼續進行右遞歸的中序查找

       3.如果右遞歸中序查找找到,就返回,否則返回null

後序查找思路:

       1.判斷當前節點的左子結點是否爲空,如果不爲空,則遞歸後序查找

       2.如果找到就返回,如果沒有找到,就判斷當前結點的右子結點是否爲空。如果不爲空,則右遞歸進行後序查找,如果找到就返回。

       3.如果左右結點都沒有找到,就和當前結點進行比較,找到就返回,否則返回Null。

代碼實現:

補充Tree接口

       注:遍歷方法在上一篇文章已經實現了,詳情請點擊上方鏈接,這篇文章就不重複敘述了。
       不過在文章的最下面,會把完整的代碼最終再發一次

public interface Tree {
    //構建樹
    void CreateBinaryTree(Object tree, Object left, Object right);
    //先序遍歷
    void PreOrder();
    //中序遍歷
    void InfixOrder();
    //後序遍歷
    void PostOrder();

    //前序查找
    Object preOrderSearch(Object root);
    //中序查找
    Object infixOrderSearch(Object root);
    //後序查找
    Object postOrder(Object root);
}

BinaryTree實現類

    //前序查找
    @Override
    public Object preOrderSearch(Object root) {
        Object res = null;
        //判斷二叉樹是否爲空
        if(root != null) {
            //比較當前是不是
            if (this.root == root) {
                return this;
            }
            //判斷當前節點左子結點是否爲空,如果不爲空,則遞歸前序查找
            //如果左遞歸找到則返回
            if(this.left != null){
                 res = left.preOrderSearch(root);
            }
            //判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
            if(res != null){
                return res;
            }
            //如果左遞歸沒找到,就繼續右遞歸查找
            if(this.right != null){
                res = right.preOrderSearch(root);
            }
        }else{
            throw new NullPointerException();
        }
        return res;
    }
    //中序查找
    @Override
    public Object infixOrderSearch(Object root) {
        Object res = null;
        //判斷二叉樹是否爲空
        if(root != null) {
            //判斷當前節點左子結點是否爲空,如果不爲空,則遞歸前序查找
            //如果左遞歸找到則返回
            if(this.left != null){
                res = left.preOrderSearch(root);
            }
            //判斷左遞歸是否找到,找到就返回,沒找到就繼續比較當前結點
            if(res != null){
                return res;
            }
            //比較當前是不是
            if (this.root == root) {
                return this;
            }
            //如果左遞歸沒找到,就繼續右遞歸查找
            if(this.right != null){
                res = right.preOrderSearch(root);
            }
        }else{
            throw new NullPointerException();
        }
        return res;
    }
    //後序查找
    @Override
    public Object postOrderSearch(Object root) {
        Object res = null;
        //判斷二叉樹是否爲空
        if(root != null) {
            //左遞歸查找,如果左遞歸找到則返回
            if(this.left != null){
                res = left.preOrderSearch(root);
            }
            //判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
            if(res != null){
                return res;
            }
            //如果左遞歸沒找到,就繼續右遞歸查找
            if(this.right != null){
                res = right.preOrderSearch(root);
            }
            //比較當前是不是
            if (this.root == root) {
                return this;
            }
        }else{
            throw new NullPointerException();
        }
        return res;
    }

    //重寫toString
    @Override
    public String toString() {
        return (String) root;
    }

測試類

        //前序查找
        Object preOrderSearch =  A.preOrderSearch("E");
        System.out.println(preOrderSearch);

        //中序查找
        Object infixOrderSearch = A.infixOrderSearch("G");
        System.out.println(infixOrderSearch);

        //後序查找
        Object postOrderSearch = A.postOrderSearch("A");
        System.out.println(postOrderSearch);

二叉樹-刪除結點

思路:

       1.因爲我們的二叉樹是單向的,所以我們是判斷當前節點的子結點是否需要刪除節點,而不能去判斷當前這個結點是不是需要刪除的節點

       2.如果當前結點的左子樹不爲空,並且左子結點就是需要刪除的結點,就將this.left=null

       3.如果當前結點的右子結點不爲空,並且右子結點就是要刪除的結點,就將this.right=null

       4.如果2,3都沒有刪除結點,那麼就需要向左子樹進行遞歸刪除

       5.如果左子樹沒有成功,就遞歸右子樹

補充Tree接口

    //刪除結點
    void remove(Object root);

BinaryTree實現類

  //遞歸刪除結點
    //1.如果刪除的結點是葉子結點,則刪除該結點
    //2.如果刪除的結點是非葉子結點,則刪除該子樹
    @Override
    public void remove(Object root) {
        //判斷二叉樹是否爲空
        if(root != null){
            //如果當前結點的左子結點不爲空,並且左子結點就是要刪除的結點,那麼就置空並返回
            if(left != null && left.root == root){
                left = null;
                return;
            }
            //如果當前結點的右子結點不爲空,並且右子結點就是要刪除的結點,那麼就置空並返回
            if(right != null && right.right == root){
                right = null;
                return;
            }
            //如果都沒有就向左子樹遞歸進行刪除
            if(left != null){
                left.remove(root);
            }
            //如果左子樹遞歸沒刪除就向右子樹遞歸刪除
            if(right != null){
                right.remove(root);
            }
        }else{
            throw new NullPointerException();
        }
    }

最終代碼

Tree接口

public interface Tree {
    //構建樹
    void CreateBinaryTree(Object tree, Object left, Object right);
    
    //先序遍歷
    void PreOrder();
    //中序遍歷
    void InfixOrder();
    //後序遍歷
    void PostOrder();

    //前序查找
    Object preOrderSearch(Object root);
    //中序查找
    Object infixOrderSearch(Object root);
    //後序查找
    Object postOrderSearch(Object root);

    //刪除結點
    void remove(Object root);
}

BinaryTree實現類

public class BinaryTree implements Tree{
    private BinaryTree left;    //左子樹
    private BinaryTree right;   //右子樹
    private Object root;        //根結點
    int count = 0;
    //-------構造傳值-------
    public BinaryTree(Object data){
        root =  data;
    }
    @Override
    //-------構建樹-------         爲了兼容接口統一Object
    public void CreateBinaryTree(Object tree, Object left, Object right){
        //強制轉換
        BinaryTree Tree = (BinaryTree) tree;
        Tree.left = (BinaryTree)left;
        Tree.right = (BinaryTree)right;
    }

    //-------先序遍歷-------
    @Override
    public void PreOrder() {
        //判斷二叉樹是否爲空
        if(root != null){
            System.out.print(root + " ");
            //判斷左子節點是否爲空
            if(left != null){
                left.PreOrder();
            }
            if(right != null){
                right.PreOrder();
            }
        }else{
            //說明樹爲空,空指針異常
            throw new NullPointerException();
        }
    }
    //-------中序遍歷-------
    @Override
    public void InfixOrder() {
        //判斷二叉樹是否爲空
        if(root != null){
            //判斷左子節點是否爲空
            if(left != null){
                left.InfixOrder();
            }
            System.out.print(root + " ");
            if(right != null){
                right.InfixOrder();
            }
        }else{
            //說明樹爲空,空指針異常
            throw new NullPointerException();
        }
    }
    //-------後序遍歷-------
    @Override
    public void PostOrder() {
        //判斷二叉樹是否爲空
        if(root != null){
            //判斷左子節點是否爲空
            if(left != null){
                left.PostOrder();
            }
            if(right != null){
                right.PostOrder();
            }
            System.out.print(root + " ");
        }else{
            //說明樹爲空,空指針異常
            throw new NullPointerException();
        }
    }

    //前序查找
    @Override
    public Object preOrderSearch(Object root) {
        Object res = null;
        //判斷二叉樹是否爲空
        if(root != null) {
            //比較當前是不是
            if (this.root == root) {
                return this;
            }
            //判斷當前節點左子節點是否爲空,如果不爲空,則遞歸前序查找
            //如果左遞歸找到則返回
            if(this.left != null){
                 res = left.preOrderSearch(root);
            }
            //判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
            if(res != null){
                return res;
            }
            //如果左遞歸沒找到,就繼續右遞歸查找
            if(this.right != null){
                res = right.preOrderSearch(root);
            }
        }else{
            throw new NullPointerException();
        }
        return res;
    }
    //中序查找
    @Override
    public Object infixOrderSearch(Object root) {
        Object res = null;
        //判斷二叉樹是否爲空
        if(root != null) {
            //判斷當前節點左子節點是否爲空,如果不爲空,則遞歸前序查找
            //如果左遞歸找到則返回
            if(this.left != null){
                res = left.preOrderSearch(root);
            }
            //判斷左遞歸是否找到,找到就返回,沒找到就繼續比較當前節點
            if(res != null){
                return res;
            }
            //比較當前是不是
            if (this.root == root) {
                return this;
            }
            //如果左遞歸沒找到,就繼續右遞歸查找
            if(this.right != null){
                res = right.preOrderSearch(root);
            }
        }else{
            throw new NullPointerException();
        }
        return res;
    }
    //後序查找
    @Override
    public Object postOrderSearch(Object root) {
        Object res = null;
        //判斷二叉樹是否爲空
        if(root != null) {
            //左遞歸查找,如果左遞歸找到則返回
            if(this.left != null){
                res = left.preOrderSearch(root);
            }
            //判斷左遞歸是否找到,找到就返回,沒找到就繼續右遞歸
            if(res != null){
                return res;
            }
            //如果左遞歸沒找到,就繼續右遞歸查找
            if(this.right != null){
                res = right.preOrderSearch(root);
            }
            //比較當前是不是
            if (this.root == root) {
                return this;
            }
        }else{
            throw new NullPointerException();
        }
        return res;
    }
    //遞歸刪除結點
    //1.如果刪除的結點是葉子結點,則刪除該結點
    //2.如果刪除的結點是非葉子結點,則刪除該子樹
    @Override
    public void remove(Object root) {
        //判斷二叉樹是否爲空
        if(root != null){
            //如果當前結點的左子結點不爲空,並且左子結點就是要刪除的結點,那麼就置空並返回
            if(left != null && left.root == root){
                left = null;
                return;
            }
            //如果當前結點的右子結點不爲空,並且右子結點就是要刪除的結點,那麼就置空並返回
            if(right != null && right.right == root){
                right = null;
                return;
            }
            //如果都沒有就向左子樹遞歸進行刪除
            if(left != null){
                left.remove(root);
            }
            //如果左子樹遞歸沒刪除就向右子樹遞歸刪除
            if(right != null){
                right.remove(root);
            }
        }else{
            throw new NullPointerException();
        }
    }

    //重寫toString
    @Override
    public String toString() {
        return (String) root;
    }
}

Test測試類

public class Test {
    public static void main(String[] args) {
        Tree A = new BinaryTree("A");
        Tree B = new BinaryTree("B");
        Tree C = new BinaryTree("C");
        Tree D = new BinaryTree("D");
        Tree E = new BinaryTree("E");
        Tree F = new BinaryTree("F");
        Tree G = new BinaryTree("G");

        A.CreateBinaryTree(A,B,C);  //定義A的兩個子節點
        A.CreateBinaryTree(B,D,E);  //定義B的兩個子節點
        A.CreateBinaryTree(C,F,G);  //定義C的兩個子節點

        //前序遍歷
        A.PreOrder();   System.out.println();
        //中序遍歷
        A.InfixOrder(); System.out.println();
        //後序遍歷
        A.PostOrder();  System.out.println();

        //前序查找
        Object preOrderSearch =  A.preOrderSearch("E");
        System.out.println(preOrderSearch);

        //中序查找
        Object infixOrderSearch = A.infixOrderSearch("G");
        System.out.println(infixOrderSearch);

        //後序查找
        Object postOrderSearch = A.postOrderSearch("A");
        System.out.println(postOrderSearch);
        //刪除測試
        A.remove("D");
        A.PreOrder();
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章