數據結構與算法:二叉排序樹

二叉排序樹

二叉排序樹(Binary Sort Tree),又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹。是數據結構中的一類。在通常狀況下,查詢效率比鏈表結構要高。node

二叉排序樹的定義數組

  • 當左子樹不爲空時,左子樹上的全部節點值都小於左子樹的根節點值數據結構

  • 當右子樹不爲空時,右子樹上的全部節點值都小於右子樹的根節點值ide

  • 若是二叉樹中有相同值節點時,能夠放在它的左子節點或右子節點(若是不是開發須要,儘可能不要有相同值的節點)this

 

插入操做

步驟:

(1) 判斷根節點是否爲空,若是爲空則將插入節點設置爲根節點spa

(2.1) 判斷插入節點值是否小於當前節點值,若是小於則往左節點走3d

(2.2) 當往左節點走時判斷左節點是否爲空,如爲空則將左節點設置爲插入節點,不爲空則跳到步驟(2)指針

(3.1) 判斷插入節點值是否大於當前節點值,若是大於則往右節點走code

(3.2) 當往右節點走時判斷右節點是否爲空,如爲空則將右節點設置爲插入節點,不爲空則跳到步驟(2)blog

下圖是將 [6, 2, 7, 1, 4, 8] 數組按順序插入二叉排序樹的過程圖示:

代碼實現

BSTNode root;//二叉排序樹的根節點

public void add(BSTNode node){
    //若是根節點爲空則,則將傳入節點設置爲根節點
    if (root == null){
        root = node;
    }else {
        add(node, root);
    }
}

/**
 * 在二叉排序樹中添加節點
 * @param node 添加的節點
 * @param pointer 輔助指針節點,初始指向根節點
 */
public void add(BSTNode node, BSTNode pointer){
    if (node == null){
        return;
    }

    if (pointer.value > node.value){//指針節點值大於添加節點值時
        //若是指針節點的左節點恰好爲空,則將添加節點插入到該左節點
        if (pointer.left == null){
            pointer.left = node;
        }else {
            //若是不是則繼續往左節點走
            add(node, pointer.left);
        }
    }else {//指針節點值小於添加節點值時
        //若是指針節點的右節點恰好爲空,則將添加節點插入到該右節點
        if (pointer.right == null){
            pointer.right = node;
        }else {
            //若是不是則繼續往右節點走
            add(node, pointer.right);
        }
    }
}

 

查找操做

步驟:

(1) 判斷當前節點是不是查找節點,若是是則直接返回當前節點

(2) 判斷當前節點值是否大於查找節點值,若是大於則往左節點查找,跳到步驟(1)

(3) 判斷當前節點值是否小於查找節點值,若是小於則往右節點查找,跳到步驟(1)

下圖是從二叉排序樹中查找值爲4的節點的圖示:

代碼實現

//根據value值查找節點
public BSTNode searchNode(int value){
    if (root == null){
        return null;
    }
    return searchNode(value, root);
}

/**
 * 根據value值查找節點
 * @param value 查找的節點
 * @param node 查找的樹
 * @return
 */
public BSTNode searchNode(int value, BSTNode node){
    //若是當前節點的值等於value時,則返回該節點
    if (node.value == value) {
        return node;
    } else if (node.value > value){//當前節點的值大於value時
        //若是該節點的左節點爲空,則表示二叉排序樹內沒有該值的節點,返回空
        if (node.left == null)
            return null;
        //左節點不爲空,繼續往左子樹查找
        return searchNode(value, node.left);
    }else {//當前節點的值小於value時
        //若是該節點的右節點爲空,則表示二叉排序樹內沒有該值的節點,返回空
        if (node.right == null)
            return null;
        //右節點不爲空,繼續往右子樹查找
        return searchNode(value, node.right);
    }
}

 

刪除操做

刪除節點可能有的3中狀態:

  • 刪除節點是葉子節點

  • 刪除節點只有左子樹爲空或右子樹爲空

  • 刪除節點左子樹和右子樹都爲空

步驟:

(1) 判斷刪除節點值是否小於當前節點值,如小於則往左節點走

(2) 判斷刪除節點值是否大於當前節點值,如大於則往右節點走

(3) 當刪除節點值等於當前節點值時,即當前節點時要刪除的節點,判斷當前節點是什麼狀態

(3.1) 當前節點是葉子節點時,則直接刪除當前節點

(3.2) 當前節點左子樹爲空時,則將右節點頂上,代替當前節點位置

(3.3) 當前節點右子樹爲空時,則將左節點頂上,代替當前節點位置

(3.4) 當前節點左子樹和右子樹都不爲空時,則將左子樹的最大值節點取出後刪除,再用最大值節點頂替當前節點位置

代碼實現

/**
 * 根據value值刪除節點
 * 刪除節點可能有的3種狀態:
 * 1.該節點是葉子節點
 * 2.該節點只有左子樹或只有右子樹
 * 3.該節點左子樹和右子樹都有
 * @param value 要刪除節點的value值
 */
public BSTNode delete(int value, BSTNode node){
    if (value < node.value){//當查找節點值小於當前節點值
        //向左子樹遞歸遍歷,並將刪除後的新的左子樹鏈接到左節點位置代替原先左子樹
        node.left = delete(value, node.left);
        //返回刪除後新的樹
        return node;
    }else if(value > node.value){//當查找節點值大於當前節點值
        //向右子樹遞歸遍歷,並將刪除後的新的右子樹鏈接到右節點位置代替原先右子樹
        node.right = delete(value, node.right);
        //返回刪除後新的樹
        return node;
    }else {//當查找節點值等於當前節點值時,即當前節點就是要刪除的節點
        //刪除節點時葉子節點的狀態
        if (node.left == null && node.right == null){
            //直接將該節點設爲空
            return null;
        }
        //刪除節點左子樹爲空,右子樹不爲空的狀態
        else if (node.left == null && node.right != null){
            //保存刪除節點的右子樹
            BSTNode rightSubTree = node.right;
            //將刪除節點的右子樹設爲空,使得該節點可以儘早被垃圾回收
            node.right = null;
            //返回刪除節點的右子樹,鏈接到刪除節點的父節點
            return rightSubTree;
        }
        //刪除節點右子樹爲空,左子樹不爲空的狀態
        else if (node.right == null && node.left != null){
            BSTNode leftSubTree = node.left;
            node.left = null;
            return leftSubTree;
        }
        //刪除節點的左子樹和右子樹都不爲空的狀態
        //這裏咱們使用的是左子樹的最大值節點代替的方法
        else {
            //獲取左子樹的最大值節點並從左子樹中刪除它
            BSTNode max = max(node.left);
            //將該最大值節點的左子樹和右子樹設置爲該節點的左子樹和右子樹
            max.left = delMax(node.left);
            max.right = node.right;
            //將刪除節點的左子樹和右子樹設爲空,使得該節點可以儘早被垃圾回收
            node.left = null;
            node.right = null;
            //執行完刪除操做後,返回以最大值節點爲根節點的新的樹,鏈接的刪除節點的父節點
            return max;
        }
    }
}

/**
 * 查找傳入節點樹下value值最大的節點並刪除該節點
 * @param node
 * @return
 */
public BSTNode delMax(BSTNode node){
    if (node.right != null){
        node.right = delMax(node.right);
        return node;
    }else {
        BSTNode leftSubTree = node.left;
        node.left = null;
        return leftSubTree;
    }
}
/**
 * 查找傳入節點樹下value值最大的節點並放回該節點
 * 在二叉排序樹中最大值的節點就是最右葉子節點
 * @param node
 * @return
 */
public BSTNode max(BSTNode node){
    BSTNode max = node;
    while (max.right != null){
        max = max.right;
    }
    return max;
}

 

完整代碼

public class BinarySortTreeDemo {
    public static void main(String[] args) {
        int array[] = {13,7,8,3,29,6,1};
        BinarySortTree binarySortTree = new BinarySortTree();
        for (int i=0; i<array.length; i++){
            binarySortTree.add(new BSTNode(array[i]));
        }
        binarySortTree.midOrder();

        System.out.println("刪除後二叉順序樹的節點:");
        binarySortTree.delete(13);
        binarySortTree.delete(7);
        binarySortTree.delete(1);
        binarySortTree.delete(29);
        binarySortTree.delete(6);

        binarySortTree.midOrder();
    }
}

//二叉排序樹
class BinarySortTree{
    BSTNode root;

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

    //添加節點
    public void add(BSTNode node){
        //若是根節點爲空則,則將傳入節點設置爲根節點
        if (root == null){
            root = node;
        }else {
            add(node, root);
        }
    }

    /**
     * 在二叉排序樹中添加節點
     * @param node 添加的節點
     * @param pointer 指針節點,初始指向根節點
     */
    public void add(BSTNode node, BSTNode pointer){
        if (node == null){
            return;
        }

        if (pointer.value > node.value){//指針節點值大於添加節點值時
            //若是指針節點的左節點恰好爲空,則將添加節點插入到該左節點
            if (pointer.left == null){
                pointer.left = node;
            }else {
                //若是不是則繼續往左節點走
                add(node, pointer.left);
            }
        }else {//指針節點值小於添加節點值時
            //若是指針節點的右節點恰好爲空,則將添加節點插入到該右節點
            if (pointer.right == null){
                pointer.right = node;
            }else {
                //若是不是則繼續往右節點走
                add(node, pointer.right);
            }
        }
    }

    //根據value值查找節點
    public BSTNode searchNode(int value){
        if (root == null){
            return null;
        }
        return searchNode(value, root);
    }

    /**
     * 根據value值查找節點
     * @param value 查找的節點
     * @param node 查找的樹
     * @return
     */
    public BSTNode searchNode(int value, BSTNode node){
        //若是當前節點的值等於value時,則返回該節點
        if (node.value == value) {
            return node;
        } else if (node.value > value){//當前節點的值大於value時
            //若是該節點的左節點爲空,則表示二叉排序樹內沒有該值的節點,返回空
            if (node.left == null)
                return null;
            //左節點不爲空,繼續往左子樹查找
            return searchNode(value, node.left);
        }else {//當前節點的值小於value時
            //若是該節點的右節點爲空,則表示二叉排序樹內沒有該值的節點,返回空
            if (node.right == null)
                return null;
            //右節點不爲空,繼續往右子樹查找
            return searchNode(value, node.right);
        }
    }


    public void delete(int value){
        //判斷刪除節點在二叉排序樹中是否存在
        BSTNode node = searchNode(value);
        if (node == null){
            throw new RuntimeException("二叉排序樹內無對應節點");
        }
        //將刪除後新的二叉排序樹更換掉原先二叉排序樹
        root = delete(value, root);
    }

    /**
     * 根據value值刪除節點
     * 刪除節點可能有的3種狀態:
     * 1.該節點是葉子節點
     * 2.該節點只有左子樹或只有右子樹
     * 3.該節點左子樹和右子樹都有
     * @param value 要刪除節點的value值
     */
    public BSTNode delete(int value, BSTNode node){
        if (value < node.value){//當查找節點值小於當前節點值
            //向左子樹遞歸遍歷,並將刪除後的新的左子樹鏈接到左節點位置代替原先左子樹
            node.left = delete(value, node.left);
            //返回刪除後新的樹
            return node;
        }else if(value > node.value){//當查找節點值大於當前節點值
            //向右子樹遞歸遍歷,並將刪除後的新的右子樹鏈接到右節點位置代替原先右子樹
            node.right = delete(value, node.right);
            //返回刪除後新的樹
            return node;
        }else {//當查找節點值等於當前節點值時,即當前節點就是要刪除的節點
            //刪除節點時葉子節點的狀態
            if (node.left == null && node.right == null){
                //直接將該節點設爲空
                return null;
            }
            //刪除節點左子樹爲空,右子樹不爲空的狀態
            else if (node.left == null && node.right != null){
                //保存刪除節點的右子樹
                BSTNode rightSubTree = node.right;
                //將刪除節點的右子樹設爲空,使得該節點可以儘早被垃圾回收
                node.right = null;
                //返回刪除節點的右子樹,鏈接到刪除節點的父節點
                return rightSubTree;
            }
            //刪除節點右子樹爲空,左子樹不爲空的狀態
            else if (node.right == null && node.left != null){
                BSTNode leftSubTree = node.left;
                node.left = null;
                return leftSubTree;
            }
            //刪除節點的左子樹和右子樹都不爲空的狀態
            //這裏咱們使用的是左子樹的最大值節點代替的方法
            else {
                //獲取左子樹的最大值節點並從左子樹中刪除它
                BSTNode max = max(node.left);
                //將該最大值節點的左子樹和右子樹設置爲該節點的左子樹和右子樹
                max.left = delMax(node.left);
                max.right = node.right;
                //將刪除節點的左子樹和右子樹設爲空,使得該節點可以儘早被垃圾回收
                node.left = null;
                node.right = null;
                //執行完刪除操做後,返回以最大值節點爲根節點的新的樹,鏈接的刪除節點的父節點
                return max;
            }
        }
    }

    /**
     * 查找傳入節點樹下value值最大的節點並刪除該節點
     * @param node
     * @return
     */
    public BSTNode delMax(BSTNode node){
        if (node.right != null){
            node.right = delMax(node.right);
            return node;
        }else {
            BSTNode leftSubTree = node.left;
            node.left = null;
            return leftSubTree;
        }
    }
    /**
     * 查找傳入節點樹下value值最大的節點並放回該節點
     * 在二叉排序樹中最大值的節點就是最右葉子節點
     * @param node
     * @return
     */
    public BSTNode max(BSTNode node){
        BSTNode max = node;
        while (max.right != null){
            max = max.right;
        }
        return max;
    }

    public void midOrder(){
        if (root != null){
            midOrder(root);
        }else {
            System.out.println("二叉順序樹爲空,沒法遍歷");
        }
    }

    //中序遍歷
    public void midOrder(BSTNode node){
        if (node.left != null){
            midOrder(node.left);
        }
        System.out.println(this);
        if (node.right != null){
            midOrder(node.right);
        }
    }
}

//二叉排序樹節點
class BSTNode{
    int value;
    BSTNode left;
    BSTNode right;

    public BSTNode(int value){
        this.value = value;
    }

    @Override
    public String toString() {
        return "BSTNode{" +
                "value=" + value +
                '}';
    }
}
相關文章
相關標籤/搜索