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


    二分查找

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

    从数组中间的元素开始,如果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

  • 相关阅读:
    Lock wait timeout exceeded; try restarting transaction
    数据库三大范式
    数据库内联和外联
    [PHP相关教程] laravel5.1学习手册[一]基本开发环境配置
    轻松实现Ecshop商城多语言切换
    php 异步提交表单
    [解决方法] php大form用post方式传递数据过多被截取的问题
    HTML5日期输入类型(date)
    PHP 数字转化为自定义长度的字符串[前插后入]
    网站应用微信登录开发指南
  • 原文地址:https://www.cnblogs.com/edwinchen/p/4794103.html
Copyright © 2020-2023  润新知