算法08 五大查找之:二叉排序樹(BSTree)


上一篇總結了索引查找,這一篇要總結的是二叉排序樹(Binary Sort Tree),又稱為二叉查找樹(Binary Search Tree) ,即BSTree。

構造一棵二叉排序樹的目的,其實並不是為了排序,而是為了提高查找和插入刪除的效率。

什么是二叉排序樹呢?二叉排序樹具有以下幾個特點。

(1)若根節點有左子樹,則左子樹的所有節點都比根節點小。

(2)若根節點有右子樹,則右子樹的所有節點都比根節點大。

(3)根節點的左,右子樹也分別是二叉排序樹。

1、二叉排序樹的圖示

下面是二叉排序樹的圖示,通過它可以加深對二叉排序樹的理解。

 

2、二叉排序樹常見的操作及思路

下面是二叉排序樹常見的操作及思路。

2-1、插入節點

思路:比如我們要插入數字20到這棵二叉排序樹中。那么步驟如下:

(1)首先將20與根節點進行比較,發現比根節點小,所以繼續與根節點的左子樹30比較。

(2)發現20比30也要小,所以繼續與30的左子樹10進行比較。

(3)發現20比10要大,所以就將20插入到10的右子樹中。

此時的二叉排序樹如下圖:

 

2-2、查找節點

比如我們要查找節點10,那么思路如下:

(1)還是一樣,首先將10與根節點50進行比較,發現比根節點要小,所以繼續與根節點的左子樹30進行比較。

(2)發現10比左子樹30要小,所以繼續與30的左子樹10進行比較。

(3)發現兩值相等,即查找成功,返回10的位置。

 

2-3、刪除節點

刪除節點的情況相對復雜,主要分為以下三種情形:

(1)刪除的是葉節點(即沒有孩子節點的)。比如20,刪除它不會破壞原來樹的結構,最簡單。如圖所示。

 

(2)刪除的是單孩子節點。比如90,刪除它后需要將它的孩子節點與自己的父節點相連。情形比第一種復雜一些。

 

(3)刪除的是有左右孩子的節點。比如根節點50

這里有一個問題就是刪除它后,誰將作為根節點?利用二叉樹的中序遍歷,就是右節點的左子樹的最左孩子

 

3、代碼

有了思路之后,下面就開始寫代碼來實現這些功能。

BSTreeNode.java

public class BSTreeNode {
    public int data;
    public BSTreeNode left;
    public BSTreeNode right;

    public BSTreeNode(int data) {
        this.data = data;
    }
}

 

BSTreeOperate.java

/**
 * 二叉排序樹的常見操作
 */
public class BSTreeOperate {

    // 樹的根節點
    public BSTreeNode root;
    // 記錄樹的節點個數
    public int size;

    /**
     * 創建二叉排序樹
     *
     * @param list
     * @return
     */
    public BSTreeNode create(int[] list) {

        for (int i = 0; i < list.length; i++) {
            insert(list[i]);
        }
        return root;
    }

    /**
     * 插入一個值為data的節點
     *
     * @param data
     */
    public void insert(int data) {
        insert(new BSTreeNode(data));
    }

    /**
     * 插入一個節點
     *
     * @param bsTreeNode
     */
    public void insert(BSTreeNode bsTreeNode) {
        if (root == null) {
            root = bsTreeNode;
            size++;
            return;
        }
        BSTreeNode current = root;
        while (true) {
            if (bsTreeNode.data <= current.data) {
                // 如果插入節點的值小於當前節點的值,說明應該插入到當前節點左子樹,而此時如果左子樹為空,就直接設置當前節點的左子樹為插入節點。
                if (current.left == null) {
                    current.left = bsTreeNode;
                    size++;
                    return;
                }
                current = current.left;
            } else {
                // 如果插入節點的值大於當前節點的值,說明應該插入到當前節點右子樹,而此時如果右子樹為空,就直接設置當前節點的右子樹為插入節點。
                if (current.right == null) {
                    current.right = bsTreeNode;
                    size++;
                    return;
                }
                current = current.right;
            }
        }
    }

    /**
     * 中序遍歷
     *
     * @param bsTreeNode
     */
    public void LDR(BSTreeNode bsTreeNode) {
        if (bsTreeNode != null) {
            // 遍歷左子樹
            LDR(bsTreeNode.left);
            // 輸出節點數據
            System.out.print(bsTreeNode.data + " ");
            // 遍歷右子樹
            LDR(bsTreeNode.right);
        }
    }

    /**
     * 查找節點
     */
    public boolean search(BSTreeNode bsTreeNode, int key) {
        // 遍歷完沒有找到,查找失敗
        if (bsTreeNode == null) {
            return false;
        }
        // 要查找的元素為當前節點,查找成功
        if (key == bsTreeNode.data) {
            return true;
        }
        // 繼續去當前節點的左子樹中查找,否則去當前節點的右子樹中查找
        if (key < bsTreeNode.data) {
            return search(bsTreeNode.left, key);
        } else {
            return search(bsTreeNode.right, key);
        }
    }
}

 

BSTreeOperateTest.java

public class BSTreeOperateTest {
    public static void main(String[] args) {
        BSTreeOperate bsTreeOperate = new BSTreeOperate();
        int[] list = new int[]{50, 30, 70, 10, 40, 90, 80};
        System.out.println("*********創建二叉排序樹*********");
        BSTreeNode bsTreeNode = bsTreeOperate.create(list);
        System.out.println("中序遍歷原始的數據:");
        bsTreeOperate.LDR(bsTreeNode);
        System.out.println("");
        System.out.println("");

        System.out.println("********查找節點*******");
        System.out.println("元素20是否在樹中:" + bsTreeOperate.search(bsTreeNode, 20));
        System.out.println("");

        System.out.println("********插入節點*******");
        System.out.println("將元素20插入到樹中");
        bsTreeOperate.insert(20);
        System.out.println("中序遍歷:");
        bsTreeOperate.LDR(bsTreeNode);
        System.out.println("");
        System.out.println("");

        System.out.println("********查找節點*******");
        System.out.println("元素20是否在樹中:" + bsTreeOperate.search(bsTreeNode, 20));
        System.out.println("");
    }
}

 

運行結果:

 

 

歡迎轉載,但請保留文章原始出處

本文地址:http://www.cnblogs.com/nnngu/p/8294714.html 

 


免責聲明!

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



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