二叉搜索樹簡介

什麼是二叉搜索樹

  對於一個任何一個節點x,它的左子樹中的關鍵字最大不超過x.key,其右子樹的關鍵字的值最小不低於x.key。前端

  例以下圖後端

  

二叉搜索樹的遍歷

  •   中序遍歷    簡單的說就是遍歷結果根節點在左子樹和右子樹之間,先遍歷根的左子樹,而後遍歷根,而後遍歷根的右子樹,若是左子樹或右子樹是一個小的樹,也是按照先左孩子,根,右孩子的順序遍歷, 例如上圖的中序遍歷結果是 2,5,6,8,9,10,11
  •   前序遍歷    簡單的說就是遍歷結果根節點在左子樹和右子樹前端,先遍歷根,而後遍歷根的左子樹,而後遍歷根的右子樹,若是左子樹或右子樹是一個小的樹,也是按照先根,左孩子,右孩子的順序遍歷, 例如上圖的中序遍歷結果是 8,5,2,6,10,9,11
  •   後序遍歷    簡單的說就是遍歷結果根節點在左子樹和右子樹後端,先遍歷根的左子樹,而後遍歷根的右子樹,最後遍歷根,若是左子樹或右子樹是一個小的樹,也是按照先左孩子,右孩子,根的順序遍歷,例如上圖的中序遍歷結果是 11,9,10,6,2,5,8

二叉搜索樹的查詢

  • 查詢 指定一個值,在一棵二叉樹中查找對應的節點。
  • 最小值 從根節點開始,一直沿着節點的left節點往下走,直到遇到NIL,這時找到節點就是
  • 最大值 從根節點開始,一直沉着節點的right節點往下走,走到遇到NIL,這時找到的節點就是
  • 前驅 一個節點的前驅是小於這個節點中的最大值的節點。
  • 後繼 一個節點的後繼是大於這個節點中的最小值的節點,

 

二叉搜索樹的插入和刪除

  • 插入   插入操做相對來講比較簡單,只要比較節點大小,若是插入的值,大於根節點,就比較根節點的右孩子,若是小於根節點,就比較根節點的左孩子,如此遞歸。最終會找到要插入的位置。
  • 刪除

   刪除比較複雜一點,咱們分三種狀況來處理,例如一棵樹T中要刪除的節點的爲z。post

  1. 若是z沒有孩子節點,那麼只要簡單地將它刪除,並修改它的父結點,
  2. 若是z只有一個孩子,那麼將這個孩子移到z的位置上,並修改z的父結點,用z的孩子來替換z。
  3. 若是z有兩個孩子,那麼找z的後繼y,並讓y移到z的位置。z的原來右子樹部分紅爲y的新的右子樹,而且z的左子樹成爲y的新的左子樹。這狀況還與y是否爲z的右孩子相關。
    1. 若是y是z的右孩子,那麼用y替換z,並公留下y的右孩子。
    2. 不然,y位於z的右子樹中但並非z的右孩子。這種狀況下,先用y的右孩子替換y,而後再用y替換z。這種狀況,就至關於刪除了y,由於這種狀況下的y不可能有兩個孩子,因此問題就又變爲1或2的狀況了。    

    

 下面是以上操做的JAVA版本提實現 。測試

 

1 表明樹節點的類this

/**
 * Created by dupang on 2017/11/12.
 */
public class TreeNode<T> {

    /**
     * 節點的左孩子
     */
    private TreeNode<T> left;
    /**
     * 節點的右孩子
     */
    private TreeNode<T> right;
    /**
     * 節點的父親
     */
    private TreeNode<T> parent;
    /**
     * 節點的值
     */
    private T value;

    public TreeNode(){

    }
    public TreeNode(TreeNode<T> left,TreeNode<T> right,TreeNode<T> parent,T value){
        this.left=left;
        this.right=right;
        this.parent=parent;
        this.value=value;
    }

    public TreeNode<T> getLeft() {
        return left;
    }

    public void setLeft(TreeNode<T> left) {
        this.left = left;
    }

    public TreeNode<T> getRight() {
        return right;
    }

    public void setRight(TreeNode<T> right) {
        this.right = right;
    }

    public TreeNode<T> getParent() {
        return parent;
    }

    public void setParent(TreeNode<T> parent) {
        this.parent = parent;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

 

 2 各個操做測試類spa

/**
 * Created by dupang on 2017/11/12.
 */
public class SearchTreeTest {
    public static void main(String[] args) {
        int[] values = new int[]{18,5,3,9,2,13,32};
        //初始化一個表示樹的根節點
        TreeNode<Integer> root = new TreeNode<>(null,null,null,null);

        //遍歷插入
        for (Integer value:values){
            //初始化要插入的節點
            TreeNode<Integer> treeNode = new TreeNode<>(null,null,null,value);
            insert(root,treeNode);
        }

        //中序遍歷
        inOrderTreeWalk(root);
        System.out.println();
        //先序遍歷
        preOrderTreeWalk(root);
        System.out.println();
        //後序遍歷
        postOrderTreeWalk(root);
        System.out.println();

        TreeNode<Integer> treeNode = treeSearch(root,3);
        //求最大值
        treeMaximum(root);
        //求最小值
        treeMinimum(root);
        //後繼
        treeSuccessor(root);
        //前驅
        treeSuccessor(root);
    }

    /**
     * 二叉搜索樹的插入操做
     * @param root 二叉樹的根
     * @param tTreeNode 要插入的節點
     */
    public static void insert(TreeNode<Integer> root,TreeNode<Integer> tTreeNode){
        //聲明一個y,用於記錄while循環中循環節點的位置,也就是插入節點要插入的位置
        TreeNode<Integer> y = null;
        //把樹的根節點賦值給x,先從根節點開始尋找插入的點。
        TreeNode<Integer> x = root;
        while (x!=null&&x.getValue()!=null){
            y=x;
            //若是要插入的值比根節點的值大,
            if(tTreeNode.getValue()>x.getValue()){
                x = x.getRight();
            }else {
                x= x.getLeft();
            }
        }
        //若是y是null,說明是個空樹
        if(y==null){
            root.setParent(null);
            root.setLeft(null);
            root.setRight(null);
            root.setValue(tTreeNode.getValue());
        }else if(tTreeNode.getValue()>y.getValue()){
            y.setRight(tTreeNode);
            tTreeNode.setParent(y);
        }else {
            y.setLeft(tTreeNode);
            tTreeNode.setParent(y);
        }
    }

    /**
     * 中序遍歷
     * @param treeNode 根節點
     */
    public static void inOrderTreeWalk(TreeNode<Integer> treeNode){
        if (treeNode!=null&&treeNode.getValue()!=null){
            inOrderTreeWalk(treeNode.getLeft());
            System.out.print(treeNode.getValue()+" ");
            inOrderTreeWalk(treeNode.getRight());
        }
    }
    /**
     * 前序遍歷
     * @param treeNode 根節點
     */
    public static void preOrderTreeWalk(TreeNode<Integer> treeNode){
        if (treeNode!=null&&treeNode.getValue()!=null){
            System.out.print(treeNode.getValue()+" ");
            inOrderTreeWalk(treeNode.getLeft());
            inOrderTreeWalk(treeNode.getRight());
        }
    }
    /**
     * 後序遍歷
     * @param treeNode 根節點
     */
    public static void postOrderTreeWalk(TreeNode<Integer> treeNode){
        if (treeNode!=null&&treeNode.getValue()!=null){
            inOrderTreeWalk(treeNode.getLeft());
            inOrderTreeWalk(treeNode.getRight());
            System.out.print(treeNode.getValue()+" ");
        }
    }

    /**
     * 在樹中查詢指定值的節點
     * @param treeNode 樹的節點
     * @param k 要查詢的值
     * @return 若是查詢到節點的值等於要查詢的值,就返回這個節點,不然返回null
     */
    public static TreeNode<Integer> treeSearch(TreeNode<Integer> treeNode,Integer k){
        if(treeNode==null||treeNode.getValue()==null||treeNode.getValue()==k){
            return treeNode;
        }
        if(k>treeNode.getValue()){
            return treeSearch(treeNode.getRight(),k);
        }else {
            return treeSearch(treeNode.getLeft(),k);
        }
    }

    /**
     * 在樹中找到最大值
     * @param treeNode 樹的節點
     * @return 若是查詢到節點的值等於要查詢的值,就返回這個節點,不然返回null
     */
    public static TreeNode<Integer> treeMaximum(TreeNode<Integer> treeNode){
        while (treeNode.getRight()!=null){
            treeNode = treeNode.getRight();
        }
        return treeNode;
    }

    /**
     * 在樹中找到最小值
     * @param treeNode 樹的節點
     * @return 若是查詢到節點的值等於要查詢的值,就返回這個節點,不然返回null
     */
    public static TreeNode<Integer> treeMinimum(TreeNode<Integer> treeNode){
        while (treeNode.getLeft()!=null){
            treeNode = treeNode.getLeft();
        }
        return treeNode;
    }

    /**
     * 找一個節點的後繼
     * @return 一個節點的後繼
     */
    public static TreeNode<Integer> treeSuccessor(TreeNode<Integer> treeNode){
        if(treeNode.getRight()!=null){
            return treeMinimum(treeNode.getRight());
        }
        TreeNode<Integer> y = treeNode.getParent();
        while (y!=null && treeNode==y.getRight()){
            treeNode = y;
            y = y.getParent();
        }
        return y;
    }
    /**
     * 找一個節點的前驅
     * @return 一個節點的前驅
     */
    public static TreeNode<Integer> treePredecessor(TreeNode<Integer> treeNode){
        if(treeNode.getLeft()!=null){
            return treeMaximum(treeNode.getLeft());
        }
        TreeNode<Integer> y = treeNode.getParent();
        while (y!=null && treeNode==y.getLeft()){
            treeNode = y;
            y = y.getParent();
        }
        return y;
    }

    public static void transplant(TreeNode<Integer> root,TreeNode<Integer> target,TreeNode<Integer> source){
        if(target.getParent()==null){
            root.setValue(source.getValue());
            root.setLeft(source.getLeft());
            root.setRight(source.getRight());
            root.setParent(source.getParent());
        }else if(target == target.getParent().getLeft()){
            target.getParent().setLeft(source);
        }else {
            target.getParent().setRight(source);
        }
        source.setParent(target.getParent());
    }

    /**
     * 從一棵樹中刪除一個節點
     * @param root 根節點
     * @param delete 要刪除的節點
     */
    public void treeDelete(TreeNode<Integer> root ,TreeNode<Integer> delete){
        if(delete.getLeft()==null){
            transplant(root,delete,delete.getRight());
        }else if(delete.getRight()==null){
            transplant(root,delete,delete.getLeft());
        }else {
            TreeNode<Integer> y = treeMinimum(delete.getRight());
            if(y.getParent()!=delete){
                transplant(root,y,y.getRight());
                y.setRight(delete.getRight());
                y.getRight().setParent(y);
            }
            transplant(root,delete,y);
            y.setLeft(delete.getLeft());
            y.getLeft().setParent(y);
        }
    }
}
相關文章
相關標籤/搜索