淺析樹結構(一)二叉查找樹(BST樹代碼實現)

二叉查找樹

二叉查找樹定義

定義:一顆二叉查找樹(BST)是一棵二叉樹,其中每個結點都含有一個Comparable的鍵(以及相關聯的值)且每個結點的鍵都大於其左子樹中的任意結點的鍵而小於右子樹的任意結點的鍵. 二叉查找樹中搜索,插入,刪除的複雜度等於樹高,即O(log(n))

二叉查找樹代碼實現

基本方法實現

import java.util.ArrayList;
import java.util.List;

public class BST <Key extends Comparable<? super Key>,Value> {
    /** 根節點 */
    private Node root;

    /** 內部節點類 */
    private class Node{
        private Key key;//鍵
        private Value value;//值
        private Node left;//左子節點
        private Node right;//右子節點
        private int N;//以該節點爲根節點的子樹中的節點總數
        Node(Key key,Value value,int N){
            this.key=key;
            this.value=value;
            this.N=N;
        }
    }
    /**
     * 整棵樹的節點數量
     * @return
     */
    public int size(){
        return size(root);
    }

    /**
     * 返回以node節點爲根的子樹的大小(節點數量)
     * @param node
     * @return
     */
    private int size(Node node){
        if(node==null){
            return 0;
        }
        return node.N;
    }

    /**
     * 更新節點的size
     * @param node
     * @return
     */
    private int updateSize(Node node){
        return size(node.left)+size(node.right)+1;
    }
}

查找某個節點的值

    /**
     * 查找樹中key對應的value值
     * @param key 要查找的key值
     * @return key對應的value值,不存在則返回null
     */
    public Value get(Key key){
        return get(root,key);
    }

    /**
     * 查找以node節點爲根節點的子樹中key對應的value值
     * @param node 要作爲根節點的節點
     * @param key 要查找的key值
     * @return key對應的value值,不存在則返回null
     */
    private Value get(Node node,Key key){
        if(node==null){
            throw new RuntimeException("Cannot find key "+key);
        }
        int compareResult = key.compareTo(node.key);
        if(compareResult<0){
            return get(node.left,key);
        }else if(compareResult>0){
            return get(node.right,key);
        }else{
            return node.value;
        }
    }

查找樹中最小的節點值

    /**
     * 查找樹中最小的key
     * @return 最小key值
     */
    public Key min(){
        return min(root).key;
    }

    /**
     * 查找以node爲根節點的子樹中最小的key
     * @param node 子樹的跟節點
     * @return 最小的key對應的node
     */
    private Node min(Node node){
        //如果樹爲空,則直接返回null
        if(node==null){
            return null;
        }
        //如果節點爲葉子節點,則返回該節點
        if(node.left==null){
            return node;
        }
        //遞歸查找最左邊的節點,也就是最小的節點
        return min(node.left);
    }

查找樹中最大的節點值

    /**
     * 查找樹中最大的key
     * @return 最大key值
     */
    public Key max(){
        return max(root).key;
    }

    /**
     * 查找以node爲根節點的子樹中最大的key
     * @param node 子樹的根節點
     * @return 最大的key對應的node
     */
    private Node max(Node node){
        if(node==null){
            return null;
        }
        if(node.right==null){
            return node;
        }
        return max(node.right);
    }

插入節點

向二叉搜索樹中插入新元素時,必須先檢測這個元素是否在樹中已經存在。如果已經存在,則不進行插入,如果元素不存在則將新元素插入到搜索停止的時候,也就是每次插入都是一個葉子節點。

    /**
     * 插入節點
     * @param key 要插入的節點的key
     * @param value 要插入的節點的value
     */
    public void put(Key key,Value value){
        root=put(root,key,value);
    }

    private Node put(Node node,Key key, Value value){
        //node==null則表示已經找到要插入新節點的地方
        if(node==null){
            return new Node(key,value,1);
        }
        int compareResult = key.compareTo(node.key);
        if(compareResult<0){
            node.left=put(node.left,key,value);
        }else if(compareResult>0){
            node.right=put(node.right,key,value);
        }else{
            node.value=value;//如果存在相同的key,則更新其value值
        }
        node.N=updateSize(node);//新增節點需要更新N值
        return node;
    }

刪除節點

要刪除的節點存在以下三種情況:

  1. 要刪除的節點爲葉子節點,即沒有子樹
  2. 要刪除的節點有且僅有一顆子樹,即有左子樹或右子樹
  3. 要刪除的節點有左右子樹.( 第3種情況比較複雜,需要找出要刪除節點的右子樹中最小的節點[或者使用左子樹中最大的節點]替換掉要刪除的節點.)
    /**
     * 刪除key對應的節點
     * @param key
     */
    public void delete(Key key){
        root=delete(root,key);
    }

    private Node delete(Node node,Key key){
        //沒有查找到
        if(node==null){
            return null;
        }
        int compareResult = key.compareTo(node.key);
        if(compareResult<0){
            //要刪除的節點位於左子樹
            node.left=delete(node.left,key);
        }else if(compareResult>0){
            //要刪除的節點位於右子樹
            node.right=delete(node.right,key);
        }else{
            /**
             *查找到要刪除的節點,分成三種情況
             * 1.要刪除的節點有左右子樹
             * 2.要刪除的節點有且僅有左子樹或者右子樹
             * 3.要刪除的節點爲葉子節點,即沒有子樹
             */
            if(node.left!=null&&node.right!=null){
                Node minOfRightTree = min(node.right);//node節點中右子樹中最小的節點
                node.key=minOfRightTree.key;//替換掉要刪除節點的key
                node.value=minOfRightTree.value;//替換掉要刪除節點的value
                node.right=delete(node.right,minOfRightTree.key);//要刪除掉node節點中右子樹中最小的節點,因此進行遞歸刪除即可。
            }else {
                //情況2和情況3均使用子節點替換掉要刪除的節點即可.
                node=node.left!=null?node.left:node.right;
            }
        }
        node.N=updateSize(node);
        return node;
    }

中序遍歷樹中節點

    public List<Key> keys(){
        ArrayList<Key> list = new ArrayList<>();
        keys(root,list);
        return list;
    }
    private void keys(Node node, ArrayList<Key> list){
        if(node==null){
            return;
        }
        keys(node.left,list);
        list.add(node.key);
        keys(node.right,list);
    }

淺析樹結構(一)二叉查找樹(BST樹代碼實現)
淺析樹結構(二)AVL平衡二叉樹(AVL樹原理及代碼實現)
淺析樹結構(三)紅黑樹

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章