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

二分查找

二分查找的原理很简单:
在一个有序数组中(本文讨论的是升序,降序同理)

从数组中间的元素开始,如果A[mid]大于被查找元素key,那么就在A[0]到A[mid-1]中查找,反之在A[mid++]到A[A.lenth - 1]中查找。

从这看来,递归的意味又很浓啊,当然也可以用非递归的方式,效率更高,意味二分查找比较简单,就直接上代码了:

定义一个查找抽象基类:

 

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);
}

 

二分查找代码:

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));
    }
    
}

 

 

对于查找来说,又两个指标比较重要,一个是插入新元素的效率,一个是查找的效率:

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

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

二叉查找树

二叉查找树简单的说,就是一个二叉树:

构建过程:

左子树所有节点小于根节点,右子树所有节点大于等于根节点(可以反过来,自己定义)

 

查找过程:

    中序遍历,如果查找到就返回。

 

其实二叉查找树也可以用来排序,和堆排序很像

 

在构建二叉查找树时,构建出来的树的形状是非常重要的,直接影响到查找的效率,如下图:

 

如最左边的图,最好的情况是一个完全二叉树,这样查找效率最高。

如最右边的图,最坏的情况会退化成一个链表,这样查找效率最低。

 

直接上代码实现:

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

 

posted @ 2015-09-09 11:23  @瞪着太阳的乌鸦  阅读(4768)  评论(0编辑  收藏  举报