自己理解的二分算法

        我们在一个集合中查询是否存在某一个元素时,经常都是通过索引一个一个的去遍历,可能集合中数据量小看不出明显的性能耗损。下面摘用了《算法图解》的案例,以便于更好的理解二分算法。

     Bob要为NASA编写一个查找算法,这个算法在火箭即将登陆月球前开
始执行,帮助计算着陆地点。

这个示例表明,两种算法的运行时间呈现不同的增速。Bob需要做出决
定,是使用简单查找还是二分查找。使用的算法必须快速而准确。一方
面,二分查找的速度更快。Bob必须在10秒钟内找出着陆地点,否则火
箭将偏离方向。另一方面,简单查找算法编写起来更容易,因此出现
bug的可能性更小。Bob可不希望引导火箭着陆的代码中有bug!为确保
万无一失,Bob决定计算两种算法在列表包含100个元素的情况下需要的
时间。
假设检查一个元素需要1毫秒。使用简单查找时,Bob必须检查100个元
素,因此需要100毫秒才能查找完毕。而使用二分查找时,只需检查7个
元素(log 2 100大约为7),因此需要7毫秒就能查找完毕。然而,实际
要查找的列表可能包含10亿个元素,在这种情况下,简单查找需要多长
时间呢?二分查找又需要多长时间呢?

       Bob使用包含10亿个元素的列表运行二分查找,运行时间为30毫秒
(log 2 1 000 000 000大约为30)。他心里想,二分查找的速度大约为简
单查找的15倍,因为列表包含100个元素时,简单查找需要100毫秒,而
二分查找需要7毫秒。因此,列表包含10亿个元素时,简单查找需要30
× 15 = 450毫秒,完全符合在10秒内查找完毕的要求。Bob决定使用简单
查找。这是正确的选择吗?
不是。实际上,Bob错了,而且错得离谱。列表包含10亿个元素时,简
单查找需要10亿毫秒,相当于11天!为什么会这样呢?因为二分查找和
简单查找的运行时间的增速不同。

也就是说,随着元素数量的增加,二分查找需要的额外时间并不多,而
简单查找需要的额外时间却很多。因此,随着列表的增长,二分查找的

速度比简单查找快得多。Bob以为二分查找速度为简单查找的15倍,这
不对:列表包含10亿个元素时,为3300万倍。有鉴于此,仅知道算法需
要多长时间才能运行完毕还不够,还需知道运行时间如何随列表增长而
增加。

把问题转换成我们开发中的场景,那就是现在有一个3亿元素的数组array(集合也行,但必须是有序的!)

用简单查找去查询

public class Test {
	public static void main(String[] args) {	
		//准备3亿数据
		long startTime=System.currentTimeMillis();   //获取开始时间
		int[] array = preparationData();	
		long endTime=System.currentTimeMillis(); //获取结束时间
		System.out.println("准备3亿数据程序运行时间: "+(endTime-startTime)+"ms");
		
		 startTime=System.currentTimeMillis();   //获取开始时间
		System.out.println(simpleAlgorithm(array, 0));
		endTime=System.currentTimeMillis(); //获取结束时间
		System.out.println("简单查找程序运行时间: "+(endTime-startTime)+"ms");
		
		startTime=System.currentTimeMillis();   //获取开始时间
		System.out.println(commonBinarySearch(array, 0));
		endTime=System.currentTimeMillis(); //获取结束时间
		System.out.println("二分查找程序运行时间: "+(endTime-startTime)+"ms");
	}
	//准备3亿数据
	public static int[] preparationData(){
		int array[] = new int[300000000];
		for(int i = 0 ; i<300000000; i++){
			array[i] = i;
		}
		System.out.println("添加数据次数:"+(array.length));
		return array;
	}
	//简单查找
	public static Integer simpleAlgorithm(int a[], int x) {
        Integer f = null ;
        int length = a.length;
        int i;
        for (i = 0; i < length ; i++) {
            if (x == a[i]) {
                f = i;
                break;
            }

        }
        if(f == null){
        	f = -1;
        }
        System.out.println("简单找数据次数:"+(f+1));
        return f;

    }
	//二分查找
	public static int commonBinarySearch(int[] arr,int key){
		int low = 0;
		int high = arr.length - 1;
		int middle = 0;			//定义middle
		int i = 0;
		if(key < arr[low] || key > arr[high] || low > high){
			return -1;				
		}	
		while(low <= high){
			middle = (low + high) / 2;
			if(arr[middle] > key){
				//比关键字大则关键字在左区域
				high = middle - 1;
			}else if(arr[middle] < key){
				//比关键字小则关键字在右区域
				low = middle + 1;
			}else{
				System.out.println("简单找数据次数:"+(i+1));
				return middle;
			}
			i++;
		}	
		
		return -1;		//最后仍然没有找到,则返回-1
	}
}

输出结果:

添加数据次数:300000000
准备3亿数据程序运行时间: 741ms
简单找数据次数:1
0
简单查找程序运行时间: 0ms
简单找数据次数:28
0
二分查找程序运行时间: 0ms

当我们查询0的时候,其实也就索引为0的位置的数据,简单查找只查了1次就返回了结果,二分查找却查了28次,

运行时间几乎都是0ms

很明显简单查找效率要高很多,如果我们现在查询1000000000,也就是索引位置为99999999的数据呢?

输出结果:

添加数据次数:300000000
准备3亿数据程序运行时间: 549ms
简单找数据次数:100000000
99999999
简单查找程序运行时间: 52ms
简单找数据次数:25
99999999
二分查找程序运行时间: 0ms

简单查找只查了100000000次就返回了结果,二分查找却查了25次,

运行时间上简单查找52ms,二分查找还是0ms

是不是感觉二分查找的优势体现出来了?我们继续查询299999999,也就是最后一个索引位置的数字

输出结果

添加数据次数:300000000
准备3亿数据程序运行时间: 627ms
简单找数据次数:300000000
299999999
简单查找程序运行时间: 128ms
简单找数据次数:29
299999999
二分查找程序运行时间: 0ms


总结:

简单查找:随着索引位置不同的数据查询效率也不同(查找顺序从左往右依次查找)

二分查找:每查询一次会排除一半的数据,直到最后只剩下一个数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值