【轉】二叉查找樹[BST]

目錄

 

二叉查找樹的特點

二叉查找樹的操作

插入操作

刪除操作

二叉查找樹的效率分析

源碼


二叉查找樹的特點

1. 如果左樹不爲空,那麼左樹上所有結點的值小於根結點的值

2. 如果右樹不爲空,那麼右樹上所有節點的值大於根結點的值

3. 左樹和右樹均是二叉查找樹,並且樹上的結點的值都不相同

二叉查找樹的操作

插入操作

將9插入到a圖的二叉樹

1> 9大於4,插入到4的右樹

2> 9大於5,插入到5的右樹,接着9還是大於6,將9插入到6的右樹

3> 9大於7,插入到7的右樹,9大於8,插入到8的右樹

在此過程中,動態增加數據都會加在原有數據的葉子節點上。

刪除操作

1. 如果這個結點的左樹存在,右樹不存在

例如

當刪除的節點在左樹:

例如,刪除a圖的節點3,只需要將結點4和結點1構成關係。表示爲 parent.left = node.left

當刪除的結點在右樹

例如,刪除c圖的結點2,只需要將結點1和結點3構成關係,表爲parent.right = node.rigtht;

2. 如果這個結點的右樹存在,左樹不存在,和上面類似。

3. 當刪除的結點,左樹和右樹都存在。

如果刪除結點5,需要一個結點能夠替換5,結點4和結點6都能夠滿足要求。

如何找到這個結點替換刪除的結點?

當前結點的左結點的走右樹,一直找到最右結點  或者是 當前結點的右結點,走左樹找到的最左結點。

源碼中展示的刪除方法,是按照 "當前結點的左結點,走右樹,找到最右結點" 的方式,編碼的。

二叉查找樹的效率分析

很顯然,在a,b兩圖的二叉查找樹結構中查找一個數據,並不需要遍歷全部的節點元素,查找效率確實提高了。但是有一個很嚴重的問題:我們在a圖中查找8需要比較5次數據,而在B圖中只需要比較3次。更爲嚴重的是:如果按有序序列[1 2 3 4 5 6 7 8]建立一顆二叉查找樹,整棵樹就退化成了一個線性結構(如c輸入圖:單支樹),此時查找8需要比較8次數據,和順序查找沒有什麼不同。

最壞的情況,時間複雜度算法是O(N),最好的情況和折半查找的時間複雜度相同,爲O(log2 (N))

源碼

package net.lingala.zip4j.test;  
import java.util.ArrayList;

import com.sun.corba.se.impl.logging.InterceptorsSystemException;  
  
/** 
 * 二叉樹節點結構 
 * @author heartraid 
 */  
class BSTNode<E extends Comparable<E>>{  
    /**結點關鍵字*/  
    E key=null;  
    /**直接父親結點*/  
    BSTNode<E> parent=null;  
    /**結點左子樹的根節點*/  
    BSTNode<E> lchild=null;  
    /**結點右子樹的根節點*/  
    BSTNode<E> rchild=null;  
      
    BSTNode(E k){  
        this.key=k;  
    }  
  
}  
/** 
 * 二叉查找樹 Binary Search Tree(BST) 
 * @author heartraid 
 * 
 */  
public class BST<E extends Comparable<E>> {  
    /**樹根*/  
    private BSTNode<E> root=null;  
      
    public BST(){  
    }  
      
    /** 
     * BST 查詢關鍵字 
     * @param key 關鍵字 
     * @return 查詢成功/true, 查詢失敗/false 
     */  
    public boolean search(E key){  
        System.out.print("搜索關鍵字["+key+"]:");  
        if(key==null||root==null){  
            System.out.println("搜索失敗");  
            return false;  
        }  
        else{  
            System.out.print("搜索路徑[");  
            if(searchBST(root,key)==null){  
                return false;  
            }  
            else return true;  
                  
        }  
    }  
    /** 
     * BST插入關鍵字 
     * @param key 關鍵字 
     * @return 插入成功/true, 插入失敗/false 
     */  
    public boolean insert(E key){  
        System.out.print("插入關鍵字["+key+"]:");  
        if(key==null) return false;  
        if(root==null){  
            System.out.println("插入到樹根。");  
            root=new BSTNode<E>(key);  
            return true;  
        }  
        else{  
            System.out.print("搜索路徑[");  
            return insertBST(root,key);  
        }  
    }  
      
    public boolean delete(E key){  
        System.out.print("刪除關鍵字["+key+"]:");  
        if(key==null||root==null){  
            System.out.println("刪除失敗");  
            return false;  
        }  
        else{  
            System.out.print("搜索路徑[");  
              
            //定位到樹中待刪除的結點  
            BSTNode<E> nodeDel=searchBST(root,key);  
            if(nodeDel==null){  
                return false;  
            }  
            else{  
                //nodeDel的右子樹爲空,則只需要重接它的左子樹  
                if(nodeDel.rchild==null){  
                      
                    BSTNode<E> parent=nodeDel.parent;  
                    if(parent.lchild.key.compareTo(nodeDel.key)==0)  
                        parent.lchild=nodeDel.lchild;  
                    else  
                        parent.rchild=nodeDel.lchild;  
                }  
                //左子樹爲空,則重接它的右子樹  
                else if(nodeDel.lchild==null){  
                    BSTNode<E> parent=nodeDel.parent;  
                    if(parent.lchild.key.compareTo(nodeDel.key)==0)  
                        parent.lchild=nodeDel.rchild;  
                    else  
                        parent.rchild=nodeDel.rchild;  
                }  
                //左右子樹均不空  
                else{  
                    BSTNode<E> q=nodeDel;  
                    //先找nodeDel的左結點s  
                    BSTNode<E> s=nodeDel.lchild;  
                    //然後再向s的右盡頭定位(這個結點將替代nodeDel),其中q一直定位在s的直接父親結點  
                    while(s.rchild!=null){   
                        q=s;  
                        s=s.rchild;  
                    }  
                    //換掉nodeDel的關鍵字爲s的關鍵字  
                    nodeDel.key=s.key;  
                    //重新設置s的左子樹  
                    if(q!=nodeDel)   
                        q.rchild=s.lchild;  
                    else  
                        q.lchild=s.lchild;  
                }  
                return true;  
            }  
        }  
    }  
      
    /** 
     * 遞歸查找關鍵子 
     * @param node 樹結點 
     * @param key 關鍵字 
     * @return 查找成功,返回該結點,否則返回null。 
     */  
    private BSTNode<E> searchBST(BSTNode<E> node, E key){  
        if(node==null){  
            System.out.println("].  搜索失敗");  
            return null;  
        }  
        System.out.print(node.key+" —>");  
        //搜索到關鍵字  
        if(node.key.compareTo(key)==0){  
            System.out.println("].  搜索成功");  
            return node;  
        }  
        //在左子樹搜索  
        else if(node.key.compareTo(key)>0){  
                return searchBST(node.lchild,key);  
        }  
        //在右子樹搜索  
        else{  
            return searchBST(node.rchild,key);  
        }  
    }  
      
    /** 
     * 遞歸插入關鍵字 
     * @param node 樹結點 
     * @param key 樹關鍵字 
     * @return true/插入成功,false/插入失敗 
     */  
    private boolean insertBST(BSTNode<E> node, E key){  
        System.out.print(node.key+" —>");  
        //在原樹中找到相同的關鍵字,無需插入。  
        if(node.key.compareTo(key)==0)   
        {  
            System.out.println("].  搜索有相同關鍵字,插入失敗");  
            return false;  
        }  
        else{  
            //搜索node的左子樹  
            if(node.key.compareTo(key)>0){  
                //如果當前node的左子樹爲空,則將新結點key node插入到左孩子處  
                if(node.lchild==null) {  
                    System.out.println("].  插入到"+node.key+"的左孩子");  
                    BSTNode<E> newNode=new BSTNode<E>(key);   
                    node.lchild=newNode;  
                    newNode.parent=node;  
                    return true;  
                }  
                //如果當前node的左子樹存在,則繼續遞歸左子樹  
                else return insertBST(node.lchild, key);  
            }  
            //搜索node的右子樹  
            else{  
                if(node.rchild==null){  
                    System.out.println("].  插入到"+node.key+"的右孩子");  
                    BSTNode<E> newNode=new BSTNode<E>(key);   
                    node.rchild=newNode;  
                    newNode.parent=node;  
                    return true;  
                }  
                else return insertBST(node.rchild,key);  
            }  
        }  
          
    }  
    /** 
     * 得到BST根節點 
     * @return BST根節點f 
     */  
    public BSTNode<E> getRoot(){  
        return this.root;  
    }  
    /** 
     * 非遞歸中序遍歷BST 
     */  
    public void InOrderTraverse(){  
        if(root==null)  
            return;  
        BSTNode<E> node=root;  
        ArrayList<BSTNode<E>> stack=new ArrayList<BSTNode<E>>();      
        stack.add(node);  
        while(!stack.isEmpty()){  
            while(node.lchild!=null){  
                node=node.lchild;  
                stack.add(node);  
            }  
            if(!stack.isEmpty()){  
                BSTNode<E> topNode=stack.get(stack.size()-1);  
                System.out.print(topNode.key+" ");  
                stack.remove(stack.size()-1);  
                if(topNode.rchild!=null){  
                    node=topNode.rchild;  
                    stack.add(node);  
                }  
            }  
        }  
          
          
    }  
      
    /** 
     * 測試 
     */  
    public static void main(String[] args) {  
        BST<Integer> tree=new BST<Integer>();  
        tree.insert(new Integer(100));  
        tree.insert(new Integer(52));  
        tree.insert(new Integer(166));  
        tree.insert(new Integer(74));  
        tree.insert(new Integer(11));  
        tree.insert(new Integer(13));  
        tree.insert(new Integer(66));  
        tree.insert(new Integer(121));  
        tree.insert(new Integer(10));
                tree.search(new Integer(11));  
                tree.InOrderTraverse();  
          
                tree.delete(new Integer(11));  
        tree.InOrderTraverse();  
  
    }  
  
}  

參考博客:https://blog.csdn.net/zxnsirius/article/details/52131433?utm_source=blogxgwz0 (關於刪除結點的查找方法)

                  http://hxraid.iteye.com/blog/609312(二叉查找樹介紹)

 

 

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