查找(一):二分查找和二叉查找树
二分查找
二分查找的原理很简单:
在一个有序数组中(本文讨论的是升序,降序同理)
从数组中间的元素开始,如果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
作者