1. 程式人生 > >玩轉資料結構(08)--二分搜尋樹

玩轉資料結構(08)--二分搜尋樹

二分搜尋樹(Binary Search Tree)

一、樹結構

使用樹結構的原因:

1.樹結構是一種天然的組織結構

            

2.資料使用樹結構儲存後,查詢高效

二叉樹:是動態資料結構【不需要在建立資料結構的時候就決定好要儲存多少資料,要新增元素就 new 一個新的空間加入到其中即可,刪除二、基礎概念同理】

    

節點 Node 中,除了要存放元素 e 之外,還要儲存兩個指向其他節點的引用 left【左孩子】right 【右孩子】

二叉樹要點:

1.二叉樹具有唯一的根節點;

2.二叉樹中每個節點最多有兩個孩子,每個節點最多有一個父親節點;一個孩子也沒有的叫做葉子節點

3.二叉樹具有天然的遞迴結構【每個節點的左子樹也是二叉樹、每個節點的右子樹也是二叉樹】

4.二叉樹不一定都是“滿”的【滿二叉樹:除葉子節點外,每個節點都有兩個孩子】

5.一個節點、甚至 NULL 也是二叉樹

二分搜尋樹:

1.二分搜尋樹是二叉樹

2.二分搜尋樹的每個節點的值:大於其左子樹的所有節點的值且小於其右子樹的所有節點的值

3.二分搜尋樹的每個子樹也是二分搜尋樹

4.儲存的元素必須具有可比較性【儲存自定義資料型別,必須自定義好資料的比較方式】

    

示例程式碼:BST.java【實現基本二分搜尋樹結構】

public class BST<E extends Comparable<E>> {		//E 要滿足Comparable介面,要有可比較性

    private class Node {	//宣告對應的節點型別
        public E e;
        public Node left, right;

        public Node(E e) {
            this.e = e;	//e為使用者傳來的e
            left = null;	//左孩子初始化
            right = null;	//右孩子初始化
        }
    }

    private Node root;	//根節點root
    private int size;	//size 記錄當前二叉樹儲存元素的數量

    public BST(){	//二分搜尋樹的建構函式
        root = null;
        size = 0;
    }

    public int size(){
        return size;
    }

    public boolean isEmpty(){	//二分搜尋樹為空
        return size == 0;
    }
}

三、向二分搜尋樹中新增元素

圖解步驟

    

  

特殊情況(有重複的話,該元素就相當於已經存在於樹中,不做任何改變)

   

  

如果想要包含重複元素,只需定義:左子樹 <= 節點;右子樹 >= 節點【只需將 = 關係放到定義中即可】

程式碼實現:BST.java

public class BST<E extends Comparable<E>> {

    private class Node {
        public E e;
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }

    private Node root;
    private int size;

    public BST(){
        root = null;
        size = 0;
    }

    public int size(){
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }

    // 向二分搜尋樹中新增新的元素e
    public void add(E e){

        if(root == null){
            root = new Node(e);		//根節點直接指向新建的元素即可
            size ++;
        }
        else
            add(root, e);	//從根節點新增新元素e
    }

    // 向以node為根的二分搜尋樹中插入元素e,遞迴演算法
    private void add(Node node, E e){	//傳入引數 Node 與 e
        if(e.equals(node.e))	//【遞迴的終止條件】傳入的e已經存在於樹中
            return;
        else if(e.compareTo(node.e) < 0 && node.left == null){	//插入的e比Node節點中的e小,插入左子樹中
            node.left = new Node(e);	//左子樹為空,直接讓node的左孩子為新插入的e
            size ++;
            return;
        }
        else if(e.compareTo(node.e) > 0 && node.right == null){//插入的e比Node節點中的e大,插入右子樹中
            node.right = new Node(e);//右子樹為空,直接讓node的右孩子為新插入的e
            size ++;
            return;
        }

        if(e.compareTo(node.e) < 0)	//遞迴呼叫,插入的e比Node節點中的e小,e插入左子樹
            add(node.left, e);
        else //e.compareTo(node.e) > 0
            add(node.right, e);	//node 的右孩子成為元素e
    }
}

精簡程式碼:BST.java( NULL 也是一個子樹)

public class BST<E extends Comparable<E>> {

    private class Node {
        public E e;
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }

    private Node root;
    private int size;

    public BST(){
        root = null;
        size = 0;
    }

    public int size(){
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }

    // 向二分搜尋樹中新增新的元素e
    public void add(E e){
        root = add(root, e);
    }

    // 向以node為根的二分搜尋樹中插入元素e,遞迴演算法
    // 返回插入新節點後二分搜尋樹的根 
    private Node add(Node node, E e){
        if(node == null){	//只要node 為null,則必須新插入節點
            size ++;
            return new Node(e); //將節點與二叉樹掛接起來
        }

        if(e.compareTo(node.e) < 0)
            node.left = add(node.left, e);	//插入元素e
        else if(e.compareTo(node.e) > 0)
            node.right = add(node.right, e);

        return node;
    }
}

四、 二分搜尋樹的查詢操作

示例程式碼:BST.java

public class BST<E extends Comparable<E>> {

    private class Node {
        public E e;
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }

    private Node root;
    private int size;

    public BST(){
        root = null;
        size = 0;
    }

    public int size(){
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }

    // 向二分搜尋樹中新增新的元素e
    public void add(E e){
        root = add(root, e);
    }

    // 向以node為根的二分搜尋樹中插入元素e,遞迴演算法
    // 返回插入新節點後二分搜尋樹的根
    private Node add(Node node, E e){
        if(node == null){
            size ++;
            return new Node(e);
        }

        if(e.compareTo(node.e) < 0)
            node.left = add(node.left, e);
        else if(e.compareTo(node.e) > 0)
            node.right = add(node.right, e);

        return node;
    }

    // 看二分搜尋樹中是否包含元素e(新增程式碼)
    public boolean contains(E e){
        return contains(root, e);
    }

    // 看以node為根的二分搜尋樹中是否包含元素e, 遞迴演算法(新增程式碼)
    private boolean contains(Node node, E e){

        if(node == null)  	// 節點為空,必然不存在
            return false;

        if(e.compareTo(node.e) == 0)	//插入元素e 與節點中的e相同
            return true;
        else if(e.compareTo(node.e) < 0)
            return contains(node.left, e);	//去node左子樹中查詢
        else // e.compareTo(node.e) > 0
            return contains(node.right, e);//去node右子樹中查詢
    }
}