二叉搜索樹(java實現)


二叉搜索樹

/**
 * 二叉搜索樹
 */
public class BinarySearchTree {
    public BinaryTreeNode<Integer> root;
    public int size;

    public BinarySearchTree() {
        this.size = 0;
    }

    //所謂生成二叉搜索樹,就是通過n次的插入結點來完成
    public BinaryTreeNode generateBST(int[] arr){
        BinarySearchTree tree = new BinarySearchTree();
        BinaryTreeNode tmp = tree.root;


        tmp = insertNode(tmp,arr[0]);   //生成根節點,要接收新的引用
        for(int i=1;i<arr.length;i++){  //從1開始
            insertNode(tmp,arr[i]);
        }
        return tmp;
    }

    //二叉搜索樹的插入  (整形的插入測試)
    public BinaryTreeNode insertNode(BinaryTreeNode node,int value){

        if(node==null){     //插入根節點
            node = new BinaryTreeNode(value);
            return node;        //返回新的引用
        }

        //插入的值比當前子樹的根結點要小(等),往左走
        //(且要判斷左孩子是否為空,為空就表示可以直接插入---因為沒有左孩子,就沒有比他更小的了)
        if(value<=(Integer) node.data&&node.lchild!=null){
            insertNode(node.lchild,value);

        }else {
            //說明左孩子為null
            if(value<=(Integer)node.data){
                node.insertLeft(value);     //插入左孩子
            }else if(value>(Integer)node.data&&node.rchild!=null){
                insertNode(node.rchild,value);
            }else{
                //說明右孩子為null
                node.insertRight(value);    //插入右孩子
            }
        }
        return null;
    }

    //層序遍歷
    public void levelTraverse() throws Exception {
        BinaryTreeNode node = root;

        CycleQueue queue = new CycleQueue(new BinaryTreeNode[100]);
        queue.enQueue(node);

        while (!queue.isEmpty()){
            BinaryTreeNode current = (BinaryTreeNode) queue.deQueue();
            System.out.printf("%5d",current.data);

            if(current.lchild!=null){
                queue.enQueue(current.lchild);
            }
            if(current.rchild!=null){
                queue.enQueue(current.rchild);
            }
        }
    }
}

測試:

        /**
         *  二叉搜索樹
         */

        BinarySearchTree searchTree = new BinarySearchTree();
        int array[] = {50,24,76,4,32,64,100};
        int array2[] = {20,40,10,80,45,60,12};

       searchTree.root =  searchTree.generateBST(array2);

        System.out.println();
        System.out.println("層序遍歷二叉搜索樹:");
        searchTree.levelTraverse();
    }

總結:

簡單來說:從根節點出發,往哪里走的問題

插入結點,生成樹其實就是不斷的插入而成

loop(node,value):

  1. 當比根節點大(往右走)
    1. 往右走如果右孩子為空,則直接插入作為右孩子
    2. 如果右孩子不為空,則遞歸進右孩子處goto loop(node.rchild,value)。繼續做根節點的左右大小比較(決定往哪走)
  2. 比根節點小(往左走)
    1. 往左走若左孩子為空,則直接插入作為左孩子
    2. 如果左孩子不為空,則遞歸進左孩子goto loop(node.lchild,value)處。把這個左孩子當作根節點,繼續做左右大小比較(決定下一步往哪走)

查找操作

    //二叉搜索樹的結點查找,判斷是否存在
    public boolean findNode(BinaryTreeNode node,int value){
        //比node.data小,往左走,且判斷左孩子是否為空
        
        if(value<(Integer)node.data&&node.lchild!=null){
            return findNode(node.lchild,value);
            
            //表示由於左孩子為空而退出的if,且value仍然<node.data,所以表示找不到指定結點
        }else if(value<(Integer)node.data){
            return false;
        }else if(value>(Integer)node.data&&node.rchild!=null){
            return findNode(node.rchild,value);
        }else if(value>(Integer)node.data){
            return false;
        }else{
            //當上面的情況都不符合,就表示屬於value==node.data的情況,所以表示找到了,返回true
            return true;
        }
    }

時間復雜度:O(log2n)

刪除操作

分析:

刪除操作分三種情況

  1. 刪除的結點無左,右孩子------可直接刪除該結點(比如parent.lchild=null即可,java中無需手動釋放資源,C和python都要釋放)
  2. 刪除的結點只有左或者右孩子中的一個---------首先判斷刪除節點是來自父節點的左孩子,還是右孩子。
    1. 被刪除的結點A是左孩子,且A結點只有左孩子,那么--- parent.lchild = A.lchild
    2. 如果被刪除結點B是右孩子,且B結點只有右孩子,那么---parent.rchild = B.rchild
  3. 刪除的結點既有左孩子,又有右孩子-----做法是找到被刪除的結點C,的右子樹中最小的結點值min_value
    1. C.value = min_value 替換值
    2. 根據這個min_value 在C.rchild為根結點的子樹中,刪除(這個刪除也就是我們定義的刪除操作,遞歸式的)這個min_value所在的結點
    //二叉搜索樹的刪除指定結點
    public boolean deleteNode(BinaryTreeNode node,int value,BinaryTreeNode parent){
        /**
         * 首先找出該結點以及記錄下他的雙親節點parent
         *  1. 第一種情況:為葉子節點, 通過parent直接刪除該節點即可 parent.lchild = null
         *  2. 第二種情況,刪除的結點有左孩子,或者右孩子,通過 如parent,parent.lchild = node.lchild,刪除
         *  3. 第三種情況,刪除的結點有左孩子,也有右孩子,通過找到這個結點右子樹中最小的結點(find_right_min)替代掉被刪除的結點,且這個最小的結點要置為null
         */

        if(value<(Integer)node.data&&node.lchild!=null){
           return  deleteNode(node.lchild,value,node);
        }else if(value<(Integer)node.data){
            return false;       //表示沒有這個結點
        }else if(value>(Integer)node.data&&node.rchild!=null){
           return  deleteNode(node.rchild,value,node);
        }else if(value>(Integer)node.data){
            return false;
        }else{
            //表示value == node.data,存在該結點

            //1. 左右孩子都不存在
            if(node.lchild==null&&node.rchild==null){
                //1.1 被刪除節點是父節點的左孩子
                if(node==parent.lchild){
                    parent.lchild = null;
                    return true;
                    //1.2 被刪除節點是父節點的右孩子
                }else{
                    parent.rchild = null;
                    return true;
                }
                //2. 左孩子存在,右孩子不在
            }else if(node.lchild!=null&&node.rchild==null){
                //2.1 當前結點是父節點的左孩子
                if(node==parent.lchild){
                    parent.lchild = node.lchild;
                    return true;
                    //2.2 當前節點是父節點的右孩子
                }else{
                    parent.rchild = node.lchild;
                    return true;
                }
                //3. 右孩子存在,左孩子不在
            }else if(node.lchild==null&&node.rchild!=null){
                //2.1 當前結點是父節點的左孩子
                if(node==parent.lchild){
                    parent.lchild = node.rchild;
                    return true;
                    //2.2 當前結點是父節點的右孩子
                }else{
                    parent.rchild = node.rchild;
                    return true;
                }
                //4. 左孩子,右孩子都在  node.lchild!=null&&node.rchild!=null
            }else{
                //4.1 找到右子樹中最小的結點值
                Integer min_value = find_min_value(node.rchild);
                //4.2 替換最小值
                node.data = min_value;
                //4.3 刪除右子樹中的最小節點
                deleteNode(node.rchild,min_value,node);
                return true;
            }
        }
    }

查找最小值

    //內部方法,用於查找最小結點值
    private Integer find_min_value(BinaryTreeNode node){
        if(node==null){
           return null;
        }
        if(node.lchild==null){
            return (Integer)node.data;
        }else{
            return find_min_value(node.lchild);
        }
    }

測試:

        int array3[] = {50,30,80,20,35,70,100,34,40,75,32,36};


        BinarySearchTree st = new BinarySearchTree();

        //注意,一定要接收這個返回的副本引用!!!
        st.root = st.generateBST(array3);

        System.out.println();
        System.out.println("bst:");
        st.levelTraverse();

        //測試刪除結點
        System.out.println();
        System.out.println("刪除35結點: ");
        st.deleteNode(st.root,35,st.root);
        st.levelTraverse();

測試結果:

原樹:

刪除35后:

​ 50

​ 30 80

​ 20 36 70 100

​ 34 40 75

​ 32

參考鏈接:https://zhuanlan.zhihu.com/p/30918614


免責聲明!

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



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