前言
在生活中,我们如果单单只是将书整理到书架上,那么我们找到一本书是比较困难的,因为我们需要一个个遍历书架上的书,但是如果我们将书按照拼音排序,那么对于我们寻找书是有帮助的,这就涉及到了我们二分查找的中一个基本思想----有序。
`
一、二分查找的定义
二分查找(Binary search)也称折半查找,是一种效率较高的查找方法。但是,二分查找要求线性表中的记录必须按关键码有序,并且必须采用顺序存储。
二、二分查找的基本思想
在有序表中,取中间记录作为比较对象。 若给定值与中间记录的关键字相等,则查找成功。
若给定值小于中间记录的关键字,则在中间记录的左半区继续查找
若给定值大于中间记录的关键字,则在中间记录的右半区继续查找 不断重复上述步骤直至查找成功
三、二分查找的方法
笔者通过粗略地学习二分算法,了解到二分算法分为两种方法,一种是左闭右闭,一种是左闭右开
这两种方法实现的功能是相同的,但是背后的逻辑却略有不同。
四、二分查找的细节
细节1
首先我们要明白:
用于查找的内容一定是有序的。也就是说,我们所需要查找的数组已经是排好顺序的
另外我们还需知道我们使用二分查找时仅仅只能查找一个元素。
在二分查找中,目标元素的查找区间是很重要的,不同的区间定义的写法是不一样的
左闭右闭 [left, right]
左闭右开 [left, right)
因为实现的功能相同,这里我着重介绍我认为更容易理解的左闭右闭的方法
细节2
重点:
且我们不需要纠结二分查找的数组中的元素是奇数个还是偶数个,
但是千万不要一直纠结中间的数字两边的数字数量不一样这个问题,因为:
两边数量不一样是一定会出现的情况
但是这种情况并不影响我们对中间数字和目标数字大小关系的判断
只要中间数字大于目标数字,就排除右边的
只要中间数字小于目标数字,就排除左边的
五、二分查找的优点
二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x.
时间复杂度即是while循环的次数。
总共有n个元素,
渐渐跟下去就是n,n/2,n/4,…n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数
由于你n/2^k取整后>=1
即令n/2^k=1
可得k=log2n,(是以2为底,n的对数)
所以时间复杂度可以表示O(h)=O(log2n)
六、二分查找的码实现
# include <stdio.h>
# include <malloc.h>
int binary_search(int* a, int key, int len)
{
int left = 0;
int right = len - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (key < a[mid])
{
right = mid - 1;//中间值大于key则查找左半区
}
else if (key > a[mid])
{
left = mid + 1;//中间值小于key则查找右半区
}
else
return mid;
}
return 0;
}
int main()
{
int n;
printf("请输入数组长度");
scanf_s("%d", &n);
int* a = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; ++i)
{
scanf_s("%d", &a[i]);
}
printf("请输入要查找的数字");
int num;
scanf_s("%d", &num);
printf("%d", binary_search(a, num, n));
return 0;
}
七、二分查找的例题
例题:
搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2 示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1 示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104 nums 为 无重复元素 的 升序 排列数组
-104 <= target <= 104
int searchInsert(int* nums, int numsSize, int target){
int left = 0;
int right = numsSize-1;
while(left<=right)
{
int mid = (left+right)/2;
if(target==nums[mid])
{
return mid;
}
if(target<nums[mid])
{
right = mid-1;
}
else if(target>nums[mid])
{
left = mid+1;
}
} return left;
//纯二分搜索[704]是返回return -1,这里要按顺序插入,所以返回left索引位置
}
总结
笔者仅仅对二分查找进行了粗略的学习,但对其中的逻辑并不能完全理解,将会在下周开始刷题强化自己的理解
本文仅用于记录笔者自己学习与进化的过程,如有错误,请不吝指出