八、二分查找(Binary Search)

匿名 (未验证) 提交于 2019-12-02 22:56:40
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012736685/article/details/83445234

一、概述

二分查找(Binary Search,也称折半查找)――针对有序数据集合的查找算法

1、基本思想

类似分治思想,每次都通过跟区间的中间元素进行对比,将代查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0(不存在该元素)。

2、时间复杂度分析――O(logn)

不妨假设数据量为n,每次查找后数据量均为原来的1/2,最坏的情况下,直到查找区间被缩小为空,才停止。设经过k次区间缩小操作区间缩小到1,可得 k=log2n 时间复杂度为O(k),也就是O(logn)。

O(1) 常量级时间复杂度的算法可能还没有O(logn)的算法执行效率高。因为:大O标记法表示时间复杂度时,会省略掉常数、系数和低阶,O(1)可能表示一个非常大的常量值,eg: O(10000)。

二、简单实现

二分查找最简单的情况:有序数组中不存在重复元素

1、递归方法实现

#include<iostream> using namespace std;  int BinarySearchRecursive(int *array, int low, int high, int key) {     if(low > high)         return -1;  	// int mid = (low + high) / 2;  若low和high比较大,两者之和就可能溢出 	int mid = low + (high - low) / 2;   	// 若性能有要求,可将除以2操作转化为位运算,以提升效率 	// int mid = low + ((high - low)>>1)      if(array[mid] == key)         return mid;     else if(array[mid] < key)         return BinarySearchRecursive(array, mid+1, high, key);     else         return BinarySearchRecursive(array, low, mid-1, key); }  int main() {     int array[10];     for(int i = 0; i < 10; i++)         array[i] = i;      cout<< "Recursive:"<<endl;     cout<<"postion:"<<BinarySearchRecursive(array,0,9,4)<<endl;     return 0; } 

2、非递归方法

int BinarySearch(int *array, int aSzie, int key) {     if(array == NULL || aSize == 0)         return -1;     int low = 0;     int high = aSize - 1;     int mid = 0;      while(low <= high)     {         mid = low + (high - low) / 2;          if(array[mid] == key)             return mid;         else if(array[mid] < key)             low = mid + 1;         else             high = mid - 1;     }     return -1; } 

3、应用场景的局限性

适用于:插入、删除操作都不频繁,一次排序多次查找且数据量较大的场景。

  • 二分查找依赖的是顺序表数据结构,也就是数组(可以按照下标随机访问元素)

  • 二分查找的数据是有序的:排序算法时间复杂度最低为O(nlogn),若动态变化的数据集合,不再适用。

  • 适合数据量较大的场景,而非特别大。因为数组为了支持随机访问的特性,要求内存空间连续。

特例:若数据之间的比较操作特别耗时,不管数据量大小,都推荐使用二分查找。同on个过尽可能较少比较次数来提升性能。

三、应用实例

1、实例

假设我们有 1000 万个整数数据,每个数据占 8 个字节,如何设计数据结构和算法,快速判断某个整数是否出现在这 1000 万数据中? 我们希望这个功能不要占用太多的内存空间,最多不要超过 100MB,你会怎么做呢?

2、分析

由于每个数据占 8 个字节,内存占用差不多为80M < 100M,符合内存限制。
==》先从小到大排序,然后利用二分查找算法找数据。

注意:散列表、二叉树这些支持快速查找的动态数据结构。但是,在该情况却不行的。虽然在大部分情况下,用二分查找可以解决的问题,用散列表、二叉树都可以解决。但是都会需要比较多的额外的内存空间。所以,如果用散列表或者二叉树来存储这
1000 万的数据,用 100MB 的内存肯定是存不下的。而二分查找底层依赖的是数组,除了数据本身之外,不需要额外存储其他信息,是最省内存空间的存储方式,所以刚好能在限定的内存大小下解决这个问题。

四、二分查找的进级(变形问题)

前提:数据都是从小到大排列的,且数据中存在重复的数据。

1、常见的变形问题

  • 查找第一个值等于给定值的元素
  • 查找最后一个值等于给定值的元素
  • 查找第一个大于等于给定值的元素
  • 查找最后一个小于等于给定值的元素

2、查找第一个值等于给定值的元素

(1)方法一

int bsearch1(int *array, int aSize, int key) {     int low = 0;     int high = aSize - 1;     while (low <= high) {         int mid = low + ((high - low)/2);         if(array[mid] > key)             high = mid - 1;         else if(array[mid] < key)             low = mid + 1;         else         // 当array[mid]=key时,         // 需要确认一下这个 array[mid] 是不是第一个值等于给定值的元素         {             // 若mid等于0,说明该元素为第一个元素;             // array[mid]的前一个元素array[mid-1]不等于key,说明该元素为第一个元素;             if((mid == 0)||(array[mid-1]!=key))                 return mid;             // 否则更新区间             else                 high = mid - 1;         }     }     return -1; } 

(2)方法二

int bsearch2(int *array, int aSize, int key) {     int low = 0;     int high = aSize - 1;          while (low <= high)     {         int mid = low + ((high - low) / 2);         if(array[mid] >= key)         {             high = mid - 1;         }         else         {             low = mid + 1;         }     }          if(array[low] == key)          return low;     else          return -1; } 

3、查找最后一个值等于给定值的元素

int bSearch(int *array,int aSize,int key) {     int low = 0;     int high = aSize - 1;     while(low <= high)     {         int mid = low + ((high - low) / 2);         if (array[mid] >= key)             high = mid - 1;         else if (array[mid < key]) {             low = mid + 1;         }         else         {             if((mid == aSize - 1)||(array[mid+1] != key))                 return mid;             else                 low = mid + 1;         }     }     return -1; } 

4、查找第一个大于等于给定值的元素

int bSearch(int *array,int aSize,int key) {     int low = 0;     int high = aSize - 1;     while(low <= high)     {         int mid = low + ((high - low) / 2);         if (array[mid] >= key)         {             if((mid == 0)||(array[mid-1] < key))                 return mid;             else                 high = mid - 1;         }         else         {             low = mid + 1;         }     }     return -1; } 

5、查找最后一个小于等于给定值的元素

int bSearch(int *array,int aSize,int key) {     int low = 0;     int high = aSize - 1;     while(low <= high)     {         int mid = low + ((high - low) / 2);         if (array[mid] > key)         {             high = mid - 1;         }         else         {             if((mid == aSize - 1)||(array[mid+1] > key))                 return mid;             else                 low = mid + 1;         }     }     return -1; } 
转载请标明出处:八、二分查找(Binary Search)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!