【追求卓越07】算法--二分查找

引导

经过前面几节排序内容,我们开始接触查找算法--二分查找。

二分查找的时间复杂度是O(logn),是一个非常高效的算法。虽然理解起来很容易,但是真正想要熟练掌握就没那么简单了。

二分查找

二分查找原理:

首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功

这和我们的归并排序,快速排序的思想是不是很相似。

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| include<stdlib.h> #include<stdio.h> #include<string.h> int binarysearch(int a[],int len , int value) { int low = 0; int high = len - 1; int mid = low + (high - low)/2; while(a[mid] != value) { if(low >= high) return -1; if(a[mid] > value) high = mid - 1; else if(a[mid] < value) low = mid + 1; mid = low + (high - low)/2; } return mid; } int main() { int a[10] = {1,5,8,10,13,15,16,18,19,20}; printf("index = %d\n",binarysearch(a,10,16)); return 0; } |

分析:

通过上面代码的实现,我相信大家对二分查找有了一定的了解。但是心细的朋友肯定会发现,这个代码只能确认数组中是否有目标值,若有相同的元素,则不能确定返回第一个。

因此接下来我们再来练习一下二分法的几个变体:

  1. 查找第一个等于给定值的元素
  2. 查找最后一个等于给定值的元素
  3. 查找第一个大于给定值的元素
  4. 查找最后一个小于给定值的元素

其实3,4就是1和2前移或后移的问题,我们主要练习前两个。

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| / *查找第一个等于给定值的元素* / int findfirstvalue(int a[],int len , int value) { int low = 0; int high = len - 1; int mid = low + (high - low)/2; while(1) { if(low > high) return -1; if(a[mid] > value) high = mid - 1; else if(a[mid] < value) low = mid + 1; else { if(mid==0 || (a[mid-1] != value)) return mid; else high = mid - 1; } mid = low + (high - low)/2; } return mid; } int main() { int a[10] = {1,5,8,10,15,15,15,18,19,20}; printf("index = %d\n",findfirstvalue(a,10,15)); return 0; } |

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| / *查找最后一个等于给定值的元素* / int findlastvalue(int a[],int len , int value) { int low = 0; int high = len - 1; int mid = low + (high - low)/2; while(1) { if(low > high) return -1; if(a[mid] > value) high = mid - 1; else if(a[mid] < value) low = mid + 1; else { if(mid==0 || (a[mid+1] != value)) return mid; else low = mid + 1; } mid = low + (high - low)/2; } return mid; } int main() { int a[10] = {1,5,8,10,15,15,15,18,19,20}; printf("index = %d\n",findlastvalue(a,10,15)); return 0; } |

注意:二分查找虽然效率很高但是它受限很多,使用起来也不是很方便,主要有以下几个原因:

  1. 二分查找依赖于数组

我们知道数组在内存中是连续存储的,如果二分查找依赖于数组。这无疑给自己造成很大的局限性。因为当数据量很大时,也就说明需要一个很大的数组,这是一个很高的要求

  1. 二分查找依赖于数据的有序,并且静态

二分查找针对的数据时有序的。当面对的数组时无序的时候该怎么办呢?我们通过之前的排序算法可以知道,排序最快通用的时间复杂度是O(nlogn)。当数组没有频繁的插入删除操作,我们先排序再二分查找,这样也是可以接受的。但是当数组面临常插入和删除的操作时,就不太适用了。会导致事件复杂度上升。

总结

本章我们开始介绍了二分查找,分析了代码实现,以及一些二分查找的变体。也介绍了二分查找适合的场景以及局限性。二分查找依赖有序的数组,对于太大或太小的数组都不太适用(太小没必要,太大没有空间)。并且不适合频繁的数据插入和删除操作。

相关推荐
今天背单词了吗9805 小时前
算法学习笔记:19.牛顿迭代法——从原理到实战,涵盖 LeetCode 与考研 408 例题
笔记·学习·算法·牛顿迭代法
没书读了5 小时前
考研复习-数据结构-第六章-图
数据结构
jdlxx_dongfangxing6 小时前
进制转换算法详解及应用
算法
why技术7 小时前
也是出息了,业务代码里面也用上算法了。
java·后端·算法
future14127 小时前
C#进阶学习日记
数据结构·学习
2501_922895587 小时前
字符函数和字符串函数(下)- 暴力匹配算法
算法
IT信息技术学习圈8 小时前
算法核心知识复习:排序算法对比 + 递归与递推深度解析(根据GESP四级题目总结)
算法·排序算法
愚润求学8 小时前
【动态规划】01背包问题
c++·算法·leetcode·动态规划
会唱歌的小黄李9 小时前
【算法】贪心算法入门
算法·贪心算法
轻语呢喃10 小时前
每日LeetCode : 两数相加--链表操作与进位的经典处理
javascript·算法