各种二分查找

来源:互联网 发布:淘宝付款后,微信立返 编辑:程序博客网 时间:2024/05/16 04:45

二分查找

给定一个有序(不降序)数组arr。

1、求任意一个i使得arr[i]等于val,不存在则返回-1

2、求最小的i使得arr[i]等于val,不存在则返回-1

3、求最大的i使得arr[i]等于val,不存在则返回-1

4、求最大的i使得arr[i]小于val,不存在则返回-1

5、求最小的i使得arr[i]大于val,不存在则返回-1

一个错误的二分查找:

[cpp] view plaincopy
  1. int bisearch(int *arr, int b, int e, int val)  
  2. {  
  3.     while(b<e)  
  4.     {   
  5.         int mid = (b+e)>>2;  
  6.         if(arr[mid] <= val)  
  7.         {  
  8.             b = mid;   
  9.         }  
  10.         else  
  11.         {  
  12.             e = mid-1;   
  13.         }   
  14.     }  
  15.     if(arr[e] == val)  
  16.     {  
  17.         return e;   
  18.     }   
  19.     else  
  20.     {  
  21.         return -1;   
  22.     }   
  23. }  

下面通过构建测试用例来找出这个程序的问题

对于所有有效输入

在arr数组中查找元素val,对于问题123构建如下的测试用例。

arr数组

找到

未找到

空集

不存在

1

1个元素

2

3

多个元素

arr中含有一个val   含有多个

位于arr开头  4        5

结尾           6        7

中间           8        9

比最小的小            10

比最大的大            11

在范围内就是不含有    12

构建测试用例

1

int a1[] = {};

cout << bisearch(a, 0, sizeof(a1)/sizeof(int)-1, 8) << endl;

2

int a2[] = {8};

cout << bisearch(a, 0, sizeof(a2)/sizeof(int)-1, 8) << endl;

3

int a3[] = {10};

cout << bisearch(a, 0, sizeof(a3)/sizeof(int)-1, 8) << endl;

4

int a4[] = {1,2,3,4,5,6,7,7,7,7,7};

cout << bisearch(a, 0, sizeof(a4)/sizeof(int)-1, 1) << endl;

5

int a5[] = {1,1,1,2,3,4,5,6,7,7,7,7,7};

cout << bisearch(a, 0, sizeof(a5)/sizeof(int)-1, 1) << endl;

6

int a6[] = {1,2,3,4,5,6,7,7,7,7,7,8};

cout << bisearch(a, 0, sizeof(a6)/sizeof(int)-1, 8) << endl;

7

int a7[] = {1,2,3,4,5,6,7,7,7,7,7,8,8,8,8};

cout << bisearch(a, 0, sizeof(a7)/sizeof(int)-1, 8) << endl;

8

int a8[] = {1,2,3,4,5,6,7,7,7,7,7,8,8,8,10,10,12};

cout << bisearch(a, 0, sizeof(a8)/sizeof(int)-1, 6) << endl;

9

int a9[] = {1,2,3,4,5,6,7,7,7,7,7,8,8,8,10,10,12};

cout << bisearch(a, 0, sizeof(a9)/sizeof(int)-1, 8) << endl;

10

int a10[] = {2,3,4,5,6,7,7,7,7,7};

cout << bisearch(a, 0, sizeof(a10)/sizeof(int)-1, 1) << endl;

11

int a11[] = {2,3,4,5,6,7,7,7,7,7};

cout << bisearch(a, 0, sizeof(a11)/sizeof(int)-1, 12) << endl;

12

int a12[] = {2,3,4,5,7,7,7,7,7};

cout << bisearch(a, 0, sizeof(a12)/sizeof(int)-1, 6) << endl;

 

期望的测试结果

测试用例编号

问题1

问题2

问题3

1

-1

-1

-1

2

0

0

0

3

-1

-1

-1

4

0

0

0

5

0-2任意

0

2

6

11

11

11

7

11-14任意

11

14

8

5

5

5

9

11-13

11

13

10

-1

-1

-1

11

-1

-1

-1

12

-1

-1

-1

对于上面那个错误程序:测试样例4进入死循环,经过分析发现,(来自编程之美)


也就是说一种情况下没有缩小范围导致。

对每一种情况都缩小范围,可以得到题目1的如下代码:可以通过全部测试样例

[cpp] view plaincopy
  1. //递归  
  2. int bisearch(int *arr, int s, int e, int val)  
  3. {  
  4.     if(s>e) return -1;  
  5.     int mid = s + ((e - s) >>1);  
  6.     if(arr[mid] == val) return mid;  
  7.     else if(arr[mid] < val) return bisearch(arr,mid+1, e, val);  
  8.     else return bisearch(arr,s, mid-1, val);  
  9. }  
  10. // 非递归  
  11. int bisearch(int *arr, int s, int e, int val)  
  12. {  
  13.     while(s<=e)  
  14.     {  
  15.         int mid = s + ((e-s)>>2);  
  16.         if(arr[mid]==val) return mid;  
  17.         else if(arr[mid]<val)  s=mid+1;  
  18.         else e=mid-1;   
  19.     }  
  20.     return -1;   
  21. }  
  22. //或者  
  23. int bisearch(int *arr, int s, int e, int val)  
  24. {  
  25.     /* 
  26.     循环结束有两种情况 
  27.     s为偶数  s=e 
  28.     s为奇数  s=e-1  
  29.     */   
  30.     while(s < e-1)  
  31.     {  
  32.         int mid = s+((e-s)>>1);  
  33.         if(arr[mid]<=val)  
  34.         {  
  35.             s=mid;   
  36.         }else{  
  37.               // 不需要e=mid-1 防止s=e   
  38.             e=mid;   
  39.         }   
  40.     }   
  41.     if(arr[s]==val)  return s;  
  42.     if(arr[e]==val)  return e;  
  43.     return -1;   
  44. }  

[cpp] view plaincopy
  1. //第二题:  
  2. int bisearch(int *arr, int s, int e, int val)  
  3. {  
  4.     while(s <= e)  
  5.     {  
  6.         if(arr[s]==val)  return s;   
  7.         int mid = s+((e-s)>>1);  
  8.         if(arr[mid]<val)  
  9.         {  
  10.             s=mid+1;   
  11.         }else if(arr[mid]==val){  
  12.             e=mid;   
  13.         } else{  
  14.             e=mid-1;   
  15.         }   
  16.     }   
  17.     return -1;   
  18. }  
  19. //第三题:  
  20. int bisearch(int *arr, int s, int e, int val)  
  21. {  
  22.     while(s <= e)  
  23.     {  
  24.         if(arr[e]==val) return e;  
  25.         int mid=s+((e-s-1)>>2)+1; // 尽量往后落,也就是3和4落在4 2和6仍然也落在4   
  26.         if(arr[mid] < val)  
  27.             s=mid+1;  
  28.         else if(arr[mid] == val)   
  29.             s=mid;  
  30.         else   
  31.             e=mid-1;   
  32.     }   
  33.     return -1;   
  34. }  

对于4,5问题不存在找不到的情况,构建测试用例

arr

val

空集

任意1

1

相等2

大于3

小于 4

多个

小于最小5

等于最小 6

在中间相等7  不等8

等于最大 9

大于最大10

 

1

int a1[] = {};

cout << bisearch(a1, 0, sizeof(a1)/sizeof(int)-1, 8) << endl;

2

int a2[] = {8};

cout << bisearch(a2, 0, sizeof(a2)/sizeof(int)-1, 8) << endl;

3

int a3[] = {10};

cout << bisearch(a3, 0, sizeof(a3)/sizeof(int)-1, 8) << endl;

4

int a4[] = {5};

cout << bisearch(a4, 0, sizeof(a4)/sizeof(int)-1, 8) << endl;

5

int a5[] = {3,5,6,7,7,7,8,8,8,8,12,18};

cout << bisearch(a5, 0, sizeof(a5)/sizeof(int)-1, 1) << endl;

6

int a6[] = {3,5,6,7,7,7,8,8,8,8,12,18};

cout << bisearch(a6, 0, sizeof(a6)/sizeof(int)-1, 3) << endl;

7

int a7[] = {3,5,6,7,7,7,8,8,8,8,12,18};

cout << bisearch(a7, 0, sizeof(a7)/sizeof(int)-1, 7) << endl;

8

int a8[] = {3,5,6,7,7,7,8,8,8,8,12,18};

cout << bisearch(a8, 0, sizeof(a8)/sizeof(int)-1, 9) << endl;

9

int a9[] = {3,5,6,7,7,7,8,8,8,8,12,18};

cout << bisearch(a9, 0, sizeof(a9)/sizeof(int)-1, 18) << endl;

10

int a10[] = {3,5,6,7,7,7,8,8,8,8,12,18};

cout << bisearch(a10, 0, sizeof(a10)/sizeof(int)-1, 20) << endl;

 

测试用例编号

问题4

问题5

1

-1

-1

2

-1

-1

3

-1

0

4

0

-1

5

-1

0

6

-1

1

7

2

6

8

9

10

9

10

-1

10

11

-1


[cpp] view plaincopy
  1. //第四题  
  2. int bisearch(int *arr, int s, int e, int val)  
  3. {  
  4.     //求最大的i使得arr[i]小于val,不存在则返回-1  
  5.     while(s<=e){  
  6.         if(arr[e]<val) return e;   
  7.         int mid = s+((e-s-1)>>1)+1;  
  8.         if(arr[mid]<val){  
  9.             s=mid;   
  10.         }   
  11.         else{  
  12.              e=mid-1;   
  13.         }              
  14.     }   
  15.     return -1;   
  16. }  
  17. //第五题  
  18. int bisearch(int *arr, int s, int e, int val)  
  19. {  
  20.     //求最小的i使得arr[i]大于val,不存在则返回-1  
  21.     while(s<=e){  
  22.         if(arr[s] > val) return s;   
  23.         int mid = s + ((e-s)>>1);   
  24.         if(arr[mid]<=val){  
  25.             s=mid+1;   
  26.         } else{  
  27.             e=mid;   
  28.         }   
  29.     }   
  30.     return -1;   
  31. }  

原文地址:点击打开链接