查找(一):二分查找和二叉查找樹

二分查找

二分查找的原理很簡單:
在一個有序數組中(本文討論的是升序,降序同理) java

從數組中間的元素開始,若是A[mid]大於被查找元素key,那麼就在A[0]到A[mid-1]中查找,反之在A[mid++]到A[A.lenth - 1]中查找。 node

從這看來,遞歸的意味又很濃啊,固然也能夠用非遞歸的方式,效率更高,意味二分查找比較簡單,就直接上代碼了: 數組

定義一個查找抽象基類:ide

 

public abstract class SearchBase {
    public Integer[] a = {0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8};
    
    //public Character[] a = {'a' ,'b' ,'c' ,'d' ,'e' ,'f' ,'g' ,'h' ,'i'};
    
    public abstract <T> Integer search(Comparable<T> key);
}

 

二分查找代碼:this

public class BinarySearch extends SearchBase {

    /* (non-Javadoc)
     * @see Search.SearchBase#search(java.lang.Comparable)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> Integer search(Comparable<T> key) {
        // TODO Auto-generated method stub
        Integer low = 0;
        Integer high = a.length - 1;
        Integer mid = (low + high)/2;
        
        while(low <= high) {
            if(key.compareTo((T) a[mid]) == 0) {
                return mid;
            } else if(key.compareTo((T) a[mid]) > 0) {
                low = ++mid;
            } else if(key.compareTo((T) a[mid]) < 0) {
                high = --mid;
            }
            mid = (low + high)/2;
        }
        
        return -1;
    }
    
    @SuppressWarnings("unchecked")
    public <T> Integer searchRecursion(Comparable<T> key,Integer low,Integer high) {
        if(low > high)
            return -1;
        Integer mid = (low + high)/2;
        if(key.compareTo((T) a[mid]) > 0)
            return searchRecursion(key,++mid,high);
        else if(key.compareTo((T) a[mid]) < 0)
            return searchRecursion(key,low,--mid);
        else
            return mid;
    }
    
    public static void main(String[] args) {
        BinarySearch binarySearch = new BinarySearch();
        System.out.println(binarySearch.searchRecursion(0,0,binarySearch.a.length-1));
    }
    
}

 

 

對於查找來講,又兩個指標比較重要,一個是插入新元素的效率,一個是查找的效率: spa

二分查找平均插入效率:O(N/2) code

二分查找平均查找效率:O(lgN) blog

二叉查找樹

二叉查找樹簡單的說,就是一個二叉樹: 排序

構建過程: 遞歸

左子樹全部節點小於根節點,右子樹全部節點大於等於根節點(能夠反過來,本身定義)

 

查找過程:

    中序遍歷,若是查找到就返回。

 

其實二叉查找樹也能夠用來排序,和堆排序很像

 

在構建二叉查找樹時,構建出來的樹的形狀是很是重要的,直接影響到查找的效率,以下圖:

 

如最左邊的圖,最好的狀況是一個徹底二叉樹,這樣查找效率最高。

如最右邊的圖,最壞的狀況會退化成一個鏈表,這樣查找效率最低。

 

直接上代碼實現:

public class BinarySearchTree extends SearchBase {
    
    class Node<T> {
        
        public Node(Comparable<T> value,Node<T> leftChile,Node<T> rightChild) {
            this.value = value;
            this.leftChild = leftChile;
            this.rightChild = rightChild;
        }
        
        Comparable<T> value = null;
        Node<T> leftChild = null;
        Node<T> rightChild = null;
    }

    @Override
    public <T> Integer search(Comparable<T> key) {
        // TODO Auto-generated method stub
        return null;
    }
    
    @SuppressWarnings("unchecked")
    public <T> T search(Comparable<T> key,Node<T> root) {
        // TODO Auto-generated method stub
        Node<T> node = root;
        while(node != null) {
            if(key.compareTo((T) node.value) < 0) {
                node = node.leftChild;
            } else if(key.compareTo((T) node.value) > 0){
                node = node.rightChild;
            } else {
                break;
            }
        }
        
        if(node == null)
            return null;
        else 
            return (T) node.value;
    }

    //向樹中添加元素
    @SuppressWarnings("unchecked")
    public <T> Node<T> addTree(Comparable<T> value,Node<T> node) {
        if(node == null)
            return new Node<T>(value,null,null);
        
        if(node.value.compareTo((T)value) > 0)
            node.leftChild = addTree(value, node.leftChild);
        else 
            node.rightChild = addTree(value, node.rightChild);
        
        return node;
    }
    
    
    //遍歷樹,輸出有序序列
    public <T> void traverseTree(Node<T> node) {
        if(node == null)
            return;
        
        traverseTree(node.leftChild);
        System.out.print(node.value);
        traverseTree(node.rightChild);
    }
    
    public static void main(String[] args) {
        BinarySearchTree binarySearchTree = new BinarySearchTree();
        Integer[] b = {1,4,2,6,7,0,3};
        
        BinarySearchTree.Node<Integer> root = binarySearchTree.new Node<Integer>(b[0],null,null);
        for(int i=1;i<b.length;i++) {
            root = binarySearchTree.addTree(b[i],root);
        }
        
        binarySearchTree.traverseTree(root);
        System.out.println();
        
        Integer result = binarySearchTree.search(1,root);
        System.out.println("result: " + result);
    }
}

 

二叉查找樹平均插入效率:1.39LgN

二叉查找樹平均查找效率:1.39LgN

相關文章
相關標籤/搜索