數(shù)據(jù)結(jié)構(gòu)之二叉排序樹(shù)整理與學(xué)習(xí)

先看一個(gè)需求

給你一個(gè)數(shù)列 (7, 3, 10, 12, 5, 1, 9),要求能夠高效的完成對(duì)數(shù)據(jù)的查詢和添加。

解決方案分析

  1. 使用數(shù)組

    數(shù)組未排序, 優(yōu)點(diǎn):直接在數(shù)組尾添加,速度快。 缺點(diǎn):查找速度慢.

    數(shù)組排序,優(yōu)點(diǎn):可以使用二分查找,查找速度快,缺點(diǎn):為了保證數(shù)組有序,在添加新數(shù)據(jù)時(shí),找到插入位置后,后面的數(shù)據(jù)需整體移動(dòng),速度慢。

  2. 使用鏈?zhǔn)酱鎯?chǔ)-鏈表

    不管鏈表是否有序,查找速度都慢,添加數(shù)據(jù)速度比數(shù)組快,不需要數(shù)據(jù)整體移動(dòng)。

3. 重點(diǎn)使用二叉排序樹(shù)

二叉排序樹(shù)介紹

二叉排序樹(shù):BST: (Binary Sort(Search) Tree), 對(duì)于二叉排序樹(shù)的任何一個(gè)非葉子節(jié)點(diǎn),要求左子節(jié)點(diǎn)的值比當(dāng)前節(jié)點(diǎn)的值小,右子節(jié)點(diǎn)的值比當(dāng)前節(jié)點(diǎn)的值大。
特別說(shuō)明:如果有相同的值,可以將該節(jié)點(diǎn)放在左子節(jié)點(diǎn)或右子節(jié)點(diǎn)

比如針對(duì)前面的數(shù)據(jù) (7, 3, 10, 12, 5, 1, 9) ,對(duì)應(yīng)的二叉排序樹(shù)為:


image

二叉排序樹(shù)創(chuàng)建和遍歷

!一個(gè)數(shù)組創(chuàng)建成對(duì)應(yīng)的二叉排序樹(shù),并使用中序遍歷二叉排序樹(shù),比如: 數(shù)組為 Array(7, 3, 10, 12, 5, 1, 9) , 創(chuàng)建成對(duì)應(yīng)的二叉排序樹(shù)為 :

代碼演示

//創(chuàng)建二叉排序樹(shù)
class BinarySortTree {

    private Node root;

    public Node getRoot() {
        return root;
    }
    //添加結(jié)點(diǎn)的方法
    public void add(Node node) {
        if(root == null) {
            root = node;//如果root為空則直接讓root指向node
        } else {
            root.add(node);
        }
    }
    //中序遍歷
    public void infixOrder() {
        if(root != null) {
            root.infixOrder();
        } else {
            System.out.println("二叉排序樹(shù)為空,不能遍歷");
        }
    }
}

//創(chuàng)建Node結(jié)點(diǎn)
class Node {
    int value;
    Node left;
    Node right;
    public Node(int value) {
        
        this.value = value;
    }

//添加結(jié)點(diǎn)的方法
    //遞歸的形式添加結(jié)點(diǎn),注意需要滿足二叉排序樹(shù)的要求
    public void add(Node node) {
        if(node == null) {
            return;
        }
        
        //判斷傳入的結(jié)點(diǎn)的值,和當(dāng)前子樹(shù)的根結(jié)點(diǎn)的值關(guān)系
        if(node.value < this.value) {
            //如果當(dāng)前結(jié)點(diǎn)左子結(jié)點(diǎn)為null
            if(this.left == null) {
                this.left = node;
            } else {
                //遞歸的向左子樹(shù)添加
                this.left.add(node);
            }
        } else { //添加的結(jié)點(diǎn)的值大于 當(dāng)前結(jié)點(diǎn)的值
            if(this.right == null) {
                this.right = node;
            } else {
                //遞歸的向右子樹(shù)添加
                this.right.add(node);
            }
            
        }
    }
    
    //中序遍歷
    public void infixOrder() {
        if(this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if(this.right != null) {
            this.right.infixOrder();
        }
    }
}

測(cè)試方法

public class BinarySortTreeDemo {
    
    public static void main(String[] args) {
        int[] arr = {7, 3, 10, 12, 5, 1, 9, 2};
        BinarySortTree binarySortTree = new BinarySortTree();
        //循環(huán)的添加結(jié)點(diǎn)到二叉排序樹(shù)
        for(int i = 0; i< arr.length; i++) {
            binarySortTree.add(new Node(arr[i]));
        }

        //中序遍歷二叉排序樹(shù)
        System.out.println("中序遍歷二叉排序樹(shù)~");
        binarySortTree.infixOrder(); // 1, 3, 5, 7, 9, 10, 12
    }

結(jié)果:

image

刪除節(jié)點(diǎn)

思路分析

image

代碼示例

//創(chuàng)建二叉排序樹(shù)
class BinarySortTree {

    private Node root;

    public Node getRoot() {
        return root;
    }

    //查找要?jiǎng)h除的結(jié)點(diǎn)
    public Node search(int value) {
        if(root == null) {
            return null;
        } else {
            return root.search(value);
        }
    }
    
    //查找父結(jié)點(diǎn)
    public Node searchParent(int value) {
        if(root == null) {
            return null;
        } else {
            return root.searchParent(value);
        }
    }
    
    //編寫方法: 
    //1. 返回的 以node 為根結(jié)點(diǎn)的二叉排序樹(shù)的最小結(jié)點(diǎn)的值
    //2. 刪除node 為根結(jié)點(diǎn)的二叉排序樹(shù)的最小結(jié)點(diǎn)
    /**
     * 
     * @param node 傳入的結(jié)點(diǎn)(當(dāng)做二叉排序樹(shù)的根結(jié)點(diǎn))
     * @return 返回的 以node 為根結(jié)點(diǎn)的二叉排序樹(shù)的最小結(jié)點(diǎn)的值
     */
    public int delRightTreeMin(Node node) {
        Node target = node;
        //循環(huán)的查找左子節(jié)點(diǎn),就會(huì)找到最小值
        while(target.left != null) {
            target = target.left;
        }
        //這時(shí) target就指向了最小結(jié)點(diǎn)
        //刪除最小結(jié)點(diǎn)
        delNode(target.value);
        return target.value;
    }
    
    
    //刪除結(jié)點(diǎn)
    public void delNode(int value) {
        if(root == null) {
            return;
        }else {
            //1.需求先去找到要?jiǎng)h除的結(jié)點(diǎn)  targetNode
            Node targetNode = search(value);
            //如果沒(méi)有找到要?jiǎng)h除的結(jié)點(diǎn)
            if(targetNode == null) {
                return;
            }
            //如果我們發(fā)現(xiàn)當(dāng)前這顆二叉排序樹(shù)只有一個(gè)結(jié)點(diǎn)
            if(root.left == null && root.right == null) {
                root = null;
                return;
            }
            
            //去找到targetNode的父結(jié)點(diǎn)
            Node parent = searchParent(value);
            //如果要?jiǎng)h除的結(jié)點(diǎn)是葉子結(jié)點(diǎn)
            if(targetNode.left == null && targetNode.right == null) {
                //判斷targetNode 是父結(jié)點(diǎn)的左子結(jié)點(diǎn),還是右子結(jié)點(diǎn)
                if(parent.left != null && parent.left.value == value) { //是左子結(jié)點(diǎn)
                    parent.left = null;
                } else if (parent.right != null && parent.right.value == value) {//是由子結(jié)點(diǎn)
                    parent.right = null;
                }
            } else if (targetNode.left != null && targetNode.right != null) { //刪除有兩顆子樹(shù)的節(jié)點(diǎn)
                int minVal = delRightTreeMin(targetNode.right);
                targetNode.value = minVal;

            } else { // 刪除只有一顆子樹(shù)的結(jié)點(diǎn)
                //如果要?jiǎng)h除的結(jié)點(diǎn)有左子結(jié)點(diǎn) 
                if(targetNode.left != null) {
                    if(parent != null) {
                        //如果 targetNode 是 parent 的左子結(jié)點(diǎn)
                        if(parent.left.value == value) {
                            parent.left = targetNode.left;
                        } else { //  targetNode 是 parent 的右子結(jié)點(diǎn)
                            parent.right = targetNode.left;
                        } 
                    } else {
                        root = targetNode.left;
                    }
                } else { //如果要?jiǎng)h除的結(jié)點(diǎn)有右子結(jié)點(diǎn) 
                    if(parent != null) {
                        //如果 targetNode 是 parent 的左子結(jié)點(diǎn)
                        if(parent.left.value == value) {
                            parent.left = targetNode.right;
                        } else { //如果 targetNode 是 parent 的右子結(jié)點(diǎn)
                            parent.right = targetNode.right;
                        }
                    } else {
                        root = targetNode.right;
                    }
                }
                
            }
            
        }
    }
    
//創(chuàng)建Node結(jié)點(diǎn)
class Node {
    int value;
    Node left;
    Node right;
    public Node(int value) {
        
        this.value = value;
    }
    
    //查找要?jiǎng)h除的結(jié)點(diǎn)
    /**
     * 
     * @param value 希望刪除的結(jié)點(diǎn)的值
     * @return 如果找到返回該結(jié)點(diǎn),否則返回null
     */
    public Node search(int value) {
        if(value == this.value) { //找到就是該結(jié)點(diǎn)
            return this;
        } else if(value < this.value) {//如果查找的值小于當(dāng)前結(jié)點(diǎn),向左子樹(shù)遞歸查找
            //如果左子結(jié)點(diǎn)為空
            if(this.left  == null) {
                return null;
            }
            return this.left.search(value);
        } else { //如果查找的值不小于當(dāng)前結(jié)點(diǎn),向右子樹(shù)遞歸查找
            if(this.right == null) {
                return null;
            }
            return this.right.search(value);
        }
        
    }
    //查找要?jiǎng)h除結(jié)點(diǎn)的父結(jié)點(diǎn)
    /**
     * 
     * @param value 要找到的結(jié)點(diǎn)的值
     * @return 返回的是要?jiǎng)h除的結(jié)點(diǎn)的父結(jié)點(diǎn),如果沒(méi)有就返回null
     */
    public Node searchParent(int value) {
        //如果當(dāng)前結(jié)點(diǎn)就是要?jiǎng)h除的結(jié)點(diǎn)的父結(jié)點(diǎn),就返回
        if((this.left != null && this.left.value == value) || 
                (this.right != null && this.right.value == value)) {
            return this;
        } else {
            //如果查找的值小于當(dāng)前結(jié)點(diǎn)的值, 并且當(dāng)前結(jié)點(diǎn)的左子結(jié)點(diǎn)不為空
            if(value < this.value && this.left != null) {
                return this.left.searchParent(value); //向左子樹(shù)遞歸查找
            } else if (value >= this.value && this.right != null) {
                return this.right.searchParent(value); //向右子樹(shù)遞歸查找
            } else {
                return null; // 沒(méi)有找到父結(jié)點(diǎn)
            }
        }
    }   
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容