前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你真的会写二分检索吗?

你真的会写二分检索吗?

作者头像
芋道源码
发布2019-10-08 16:40:32
3320
发布2019-10-08 16:40:32
举报
文章被收录于专栏:芋道源码1024芋道源码1024

来源:http://t.cn/EiwP9qJ

  • 1. 找出第一个与key相等的元素
  • 2. 找出最后一个与key相等的元素
  • 3. 查找第一个等于或者大于Key的元素
  • 4. 查找第一个大于key的元素
  • 5. 查找最后一个等于或者小于key的元素
  • 6. 查找最后一个小于key的元素

前几天在论坛上看到有统计说有80%的程序员不能够写对简单的二分法。二分法不是很简单的吗?这难道不是耸人听闻?

其实,二分法真的不那么简单,尤其是二分法的各个变种。最最简单的二分法,就是从一个排好序的数组之查找一个key值。如下面的程序:

1. int search(int *arr, int n, int key)
2. {
3.     int left = 0, right = n-1;
4.     while(left<=right) {
5.         int mid = left + ((right - left) << 1);
6.         if (arr[mid] == key) return mid;
7.         else if(arr[mid] > key) right = mid - 1;
8.         else left = mid + 1;
9.     }
10.     return -1;
11. }

这个程序,相信只要是一个合格的程序员应该都会写。稍微注意一点, 每次移动left和right指针的时候,需要在mid的基础上+1或者-1, 防止出现死循环, 程序也就能够正确的运行。

但如果条件稍微变化一下, 你还会写吗?如,数组之中的数据可能可以重复,要求返回匹配的数据的最小(或最大)的下标;更近一步, 需要找出数组中第一个大于key的元素(也就是最小的大于key的元素的)下标,等等。这些,虽然只有一点点的变化,实现的时候确实要更加的细心。下面列出了这些二分检索变种的实现。

1. 找出第一个与key相等的元素

1. int searchFirstEqual(int *arr, int n, int key)
2. {
3.     int left = 0, right = n-1;
4.     while(left<=right) {
5.         int mid = (left+right)/2;
6.         if(arr[mid] >= key) right = mid - 1;
7.         else if(arr[mid] < key) left = mid + 1;
8.     }
9.     if( left < n && arr[left] == key) return left;
10.     return -1;
11. }

2. 找出最后一个与key相等的元素

1. int searchLastEqual(int *arr, int n, int key)
2. {
3.     int left = 0, right = n-1;
4.     while(left<=right) {
5.         int mid = (left+right)/2;
6.         if(arr[mid] > key) right = mid - 1;
7.         else if(arr[mid] <= key) left = mid + 1;
8.     }
9.     if( right>=0 && arr[right] == key) return right;
10.     return -1;
11. }

3. 查找第一个等于或者大于Key的元素

1. int searchFirstEqualOrLarger(int *arr, int n, int key)
2. {
3.     int left=0, right=n-1;
4.     while(left<=right) {
5.         int mid = (left+right)/2;
6.         if(arr[mid] >= key) right = mid-1;
7.         else if (arr[mid] < key) left = mid+1;
8.     }
9.     return left;
10. }

4. 查找第一个大于key的元素

1. int searchFirstLarger(int *arr, int n, int key)
2. {
3.     int left=0, right=n-1;
4.     while(left<=right) {
5.         int mid = (left+right)/2;
6.         if(arr[mid] > key) right = mid-1;
7.         else if (arr[mid] <= key) left = mid+1;
8.     }
9.     return left;
10. }

5. 查找最后一个等于或者小于key的元素

1. int searchLastEqualOrSmaller(int *arr, int n, int key)
2. {
3.     int left=0, right=n-1;
4.     while(left<=right) {
5.         int m = (left+right)/2;
6.         if(arr[m] > key) right = m-1;
7.         else if (arr[m] <= key) left = m+1;
8.     }
9.     return right;
10. }

6. 查找最后一个小于key的元素

1. int searchLastSmaller(int *arr, int n, int key)
2. {
3.     int left=0, right=n-1;
4.     while(left<=right) {
5.         int mid = (left+right)/2;
6.         if(arr[mid] >= key) right = mid-1;
7.         else if (arr[mid] < key) left = mid+1;
8.     }
9.     return right;
10. }

下面是一个测试的例子:

1. int main(void)
2. {
3.     int arr[17] = {1,
4.                    2, 2, 5, 5, 5,
5.                    5, 5, 5, 5, 5,
6.                    5, 5, 6, 6, 7};
7.     printf("First Equal           : %2d \n", searchFirstEqual(arr, 16, 5));
8.     printf("Last Equal            : %2d \n", searchLastEqual(arr, 16, 5));
9.     printf("First Equal or Larger : %2d \n", searchFirstEqualOrLarger(arr, 16, 5));
10.     printf("First Larger          : %2d \n", searchFirstLarger(arr, 16, 5));
11.     printf("Last Equal or Smaller : %2d \n", searchLastEqualOrSmaller(arr, 16, 5));
12.     printf("Last Smaller          : %2d \n", searchLastSmaller(arr, 16, 5));
13.     system("pause");
14.     return 0;
15. }

最后输出结果是:

1. First Equal           :  3
2. Last Equal            : 12
3. First Equal or Larger :  3
4. First Larger          : 13
5. Last Equal or Smaller : 12
6. Last Smaller          :  2

很多的时候,应用二分检索的地方都不是直接的查找和key相等的元素,而是使用上面提到的二分检索的各个变种,熟练掌握了这些变种,当你再次使用二分检索的检索的时候就会感觉的更加的得心应手了。



本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芋道源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 找出第一个与key相等的元素
  • 2. 找出最后一个与key相等的元素
  • 3. 查找第一个等于或者大于Key的元素
  • 4. 查找第一个大于key的元素
  • 5. 查找最后一个等于或者小于key的元素
  • 6. 查找最后一个小于key的元素
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档