黑马程序员技术交流社区

标题: 二分法binarySearch探究与改进 [打印本页]

作者: Aaron_wang    时间: 2015-11-21 00:38
标题: 二分法binarySearch探究与改进
本帖最后由 Aaron_wang 于 2015-11-21 00:38 编辑

相比于笨拙的遍历数组,二分法是对数组中元素查找效率很高的一种方法,但前提是数组本身是有序的,且只能返回一个索引,这样的话,二分法虽然高效却不能对含重复元素的数组的元素索引进行全部获取,也就是说,某个元素在数组中出现2次或两次以上,二分法查找此元素索引只能随机获取其中的一个,这样的话,很不爽~。
下面给出的改进的二分法可以返回该重复元素的所有索引,并且和遍历数组方法进行了性能上的比较,数据量比较小时遍历数组用时较少,因为一方面,改进的二分法逻辑判断较多,另一方面,数据太少二分法体现不出高效;而数据量较大时,改进的二分法速度上明显优于数组遍历!
  1. import java.util.Arrays;

  2. public class ArraysDemo2 {

  3.         
  4.          * 需求:编程实现二分法查找并改进
  5.          *
  6.          * @author Aaron
  7.          * @verson 2015-11-19 14:07:17
  8.          */
  9.         public static void main(String[] args) {
  10.                
  11. //                int[] arr = {23,4,4,12,21,44,1,99,34};//小数据
  12.                 int[] arr = new int[200000];//大量数据
  13.                 for(int i=0; i<arr.length; i=i+2){
  14.                         arr[i] = i;
  15.                         arr[i+1] = i;
  16.                 }

  17.                 //选择排序,对小数据先排个序
  18.                 xuanZe(arr);
  19. //                System.out.println(Arrays.toString(arr));
  20.                
  21.                 //普通二分法查找元素,若没找到,返回该数字插入数组时排序位置的负数减1
  22.                 int index = myBinarySearch(arr,4);
  23.                 System.out.println(index);
  24.                
  25.                 //二分法改进,能返回重复元素的角标数组,如果没有,返回数字插入数组时排序索引的负数减
  26.                 long start = System.currentTimeMillis();
  27.                 int[] superIndex = superBinarySearch(arr,130);
  28.                 for(int index1 : superIndex)
  29.                         System.out.print(index1+" ");
  30.                 long end = System.currentTimeMillis();
  31.                 System.out.println("改进的二分法用时"+(end-start)+"毫秒!");
  32.                
  33.                 //遍历数组方法获取某元素所在角标集合,如果没有,返回只含-1元素的数组
  34.                 long start1 = System.currentTimeMillis();
  35.                 int[] index2;
  36.                 index2 = indexSearch(arr,130);
  37.                 for(int index1 : index2)
  38.                         System.out.print(index1+" ");
  39.                 long end1 = System.currentTimeMillis();
  40.                 System.out.println("遍历数组方法用时"+(end1-start1)+"毫秒!");
  41.         }
  42.         
  43. //遍历数组
  44.         private static int[] indexSearch(int[] arr, int num) {
  45.                 int[] index = new int[arr.length];
  46.                 Arrays.fill(index, -1);
  47.                 int pos = 0;
  48.                 for(int i=0; i<arr.length; i++){
  49.                         if(arr[i]==num)
  50.                                 index[pos++] = i;
  51.                 }
  52.                 if(pos==0)
  53.                         return Arrays.copyOf(index, 1);
  54.                 return Arrays.copyOf(index,pos);
  55.         }

  56. //改进二分法
  57.         private static int[] superBinarySearch(int[] arr, int num) {
  58.                 int start = 0;
  59.                 int end = arr.length-1;
  60.                 int mid;
  61.                 int[] index = new int[arr.length];
  62.                 Arrays.fill(index, -1);
  63.                 int pos = 0;//角标数组的指针位置,存一次加一次,最后按位置截取
  64.                
  65.                 while(start<=end){
  66.                         if(arr[start]==num){
  67.                                 index[pos++] = start;
  68.                                 while(arr[++start]==num)
  69.                                         index[pos++] = start;
  70.                                 return Arrays.copyOf(index, pos);
  71.                         }
  72.                         if(arr[end]==num){
  73.                                 index[pos++] = end;
  74.                                 while(arr[--end]==num)
  75.                                         index[pos++] = end;
  76.                                 return Arrays.copyOf(index, pos);
  77.                         }
  78.                         mid = (start+end)/2;
  79.                         if(arr[mid]>num)
  80.                                 end = mid-1;
  81.                         else if(arr[mid]<num)
  82.                                 start = mid+1;
  83.                         else if(arr[mid]==num){
  84.                                 int midback = mid-1;
  85.                                 while(arr[midback--]==num)
  86.                                         index[pos++] = midback;
  87.                                 index[pos++] = mid;
  88.                                 while(arr[++mid]==num)
  89.                                         index[pos++] = mid;
  90.                                 return Arrays.copyOf(index, pos);
  91.                         }
  92.                 }
  93.                 index[pos++] = -start-1;
  94.                 return Arrays.copyOf(index, pos);
  95.         }

  96. //一般二分法
  97.         private static int myBinarySearch(int[] arr,int num) {
  98.                 int start = 0;
  99.                 int end = arr.length-1;
  100.                 int mid;
  101.                 while(start<=end){
  102.                         if(arr[start]==num)
  103.                                 return start;
  104.                         if(arr[end]==num)
  105.                                 return end;
  106.                         mid = (start+end)/2;
  107.                         if(arr[mid]>num){
  108.                                 end = mid-1;
  109.                         }else if(arr[mid]<num){
  110.                                 start = mid+1;
  111.                         }else return mid;
  112.                                 
  113.                 }
  114.                 return -start-1;
  115.         }

  116. //选择排序
  117.         private static void xuanZe(int[] arr) {
  118.                 int temp;
  119.                 for (int i = 0; i < arr.length-1; i++) { //循环次数
  120.                         for (int j = i; j < arr.length; j++) { //每次大循环从前往后确定一个最小值
  121.                                 if(arr[i]>arr[j]){
  122.                                         temp = arr[i];
  123.                                         arr[i] = arr[j];
  124.                                         arr[j] = temp;
  125.                                 }
  126.                         }
  127.                 }
  128.         }
  129. }
复制代码
运行结果:
5      ------这是二分法的
131 130 改进的二分法用时5毫秒!
130 131 遍历数组方法用时8毫秒!

是不是快了许多,如果将测试数据130改为-130,数组中并不存在的数据,结果为:
5
-1 改进的二分法用时4毫秒!
-1 遍历数组方法用时8毫秒




作者: Aaron_wang    时间: 2015-11-21 23:33
怎么没人呐,啊啊啊啊
作者: xiaoniu706    时间: 2015-11-22 00:28
顶顶顶顶




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2