你真的会二分查找吗?

本文深入探讨二分查找算法的不同实现方式,重点分析了四种常见情况:YES_LEFT、YES_RIGHT、NO_LEFT、NO_RIGHT,并提供了相应的代码示例。

引用请注明出处:http://blog.youkuaiyun.com/int64ago/article/details/7425727

       看到这个标题无论你是处于怎样的心理进来看了,我觉得都是值得的。因为这个问题太简单,任何一个开始接触“真正”算法基本都是从二分查找开始的。至于二分查找都不知道是什么的可以先去找别的资料看下,再来看这篇文章。既然很简单,那么我们开始一起写一个吧,要求是对num[]={1,2,2,4,4,8,10}不减序列在区间[0,7)进行查找,当然我们得首先保证要查找的数e满足:num[0] <= e <= num[0],这个是很容易做到的,为了简化又不失去代表性,e选取2、3、4这三个数。我们就一起开始写吧:

       首先,很容易的写下 int bSearch(int begin, int end, int e)

       然后,很自然的定义 int mid, left = begin, right = end;

       接下来怎么写呢?while(left < right)?while(left <= right)?while(mid == left)?while(mid == right)?………………真正一个写程序人会想纠结好一会儿,我们就选一个吧while(left < right)

       下面,也很自然,min = (left + right) >> 1; 用位云算能节省一些时间呢!

        现在呢?又是纠结的时候了吧?if(num[mid] > e)?if(num[mid] >= e)?我们也随便选一个吧,if(num[mid] > e)

        其实,下面你会不断纠结……right = mid;这是正常人的写法,但是有时候也会看到别人写成right = mid - 1;我们也考虑下吧,但是现在我们就直接写right = mid;

        有if了当然也会有else,然后理所当然 left = mid;同样记住还有一个选择left = mid + 1;


不错,整个while循环搞定了,最后就是返回了,写下return的时候是不是又纠结了?left?right?mid?算了,就写mid吧,整个程序就写好了,如下:

int bSearch(int begin, int end, int e)
{
	int mid, left = begin, right = end;
	while(left < right)
	{
		mid = (left + right) >> 1;
		if(num[mid] > e) right = mid;
		else left = mid;
	}
	return mid;
}

       补充好整个程序后运行吧!查找2、3、4的时候都没有结果出现!!比如查4的时候,单步调试会发现当mid=4,left=4,right=5,接下来就一直在while里循环,保持不变!问题到底在哪?问题在很多地方,因为我们上面的遇到很多选择,没有结果是多个选择作用的共同的结果,通过修修补补也可以得到想要的结果,其它例子就不举了,直接说说本文章讨论的关键吧。我总结的二分无非就4种情况:YES_LEFT、YES_RIGHT、NO_LEFT、NO_RIGHT,分别代表:能找到且返回最左边的数的位置(如查找4的时候返回位置3)、能找到且返回最右边的数的位置(如查找4的时候返回位置4)、不能找到且返回左边与其接近的数的位置(如查找3的时候返回位置2)、不能找到且返回右边与其接近的数的位置(如查找3的时候返回位置3)。下面是我总结调试的代码:


对于YES_LEFT或者NO_RIGHT

int bSearch(int begin, int end, int e)
{
	int mid, left = begin, right = end;
	while(left <= right)
	{
		mid = (left + right) >> 1;
		if(num[mid] >= e) right = mid - 1;
		else left = mid + 1;
	}
	return left;
}
对于YES_RIGHT或者NO_LEFT

int bSearch(int begin, int end, int e)
{
	int mid, left = begin, right = end;
	while(left <= right)
	{
		mid = (left + right) >> 1;
		if(num[mid] > e) right = mid - 1;
		else left = mid + 1;
	}
	return right;
}

      不做过多说明,单步调试自然会发现执行过程,要说明的是,两个程序都用了right = mid - 1; left = mid +1;用这个的前提是终止条件要是left <= right。要注意的是,有的二分查找不是只需要四种情况中的一种,而是组合使用,比如查找一个数,如果找到则×××不然则×××,如果是YES_LEFT || NO_RIGHT组合或者YES_RIGHT || NO_LEFT组合就直接用上面代码即可,否则就要综合用了,加一些判断等说明,因为用的时候不多,就不给出代码了,自己如果遇到可以试着写写,当成模板,以后直接用~

       现在,是不是觉得二分查找很容易呢?如果总结过的话……


<think>首先,用户的问题是:“find是二分查找吗?”这是一个关于编程概念的问题。用户想知道“find”是否指的是二分查找。 回想一下,“find”这个词在编程中很常见,但通常不是特指二分查找。例如: - 在Python中,有 `find()` 方法用于字符串,它返回子字符串的索引。 - 在C++中,有 `std::find()` 算法,用于在序列中查找元素,但它通常是线性查找。 - 在Java中,有 `indexOf()` 或类似方法。 二分查找(Binary Search)是一种特定的算法,用于在有序数组中查找元素,时间复杂度为O(log n)。它要求数组是排序的。 所以,回答应该是:不,通常“find”不是指二分查找。它可能表示线性查找或其他查找方法,具体取决于上下文。 现在,根据用户的指示,我需要: - 详尽地给出解决方案。 - 尽可能提供代码,并用Markdown格式包裹。 - 解释代码。 - 最后提出相关问题,格式严格遵循:§§相关问题§§: 然后1. 2. 3. 4. 回答流程: 1. 回答问题:直接回应问题。 2. 给出解释:详细解释为什么。 3. 提供代码示例:展示二分查找的实现,以区分它。 4. 解释代码:说明代码的工作原理。 5. 最后,提出相关问题。 代码示例:我将使用Python实现二分查找,因为它是常见的语言。 相关问题:基于主题,我应该提出与查找算法相关的问题。例如: 1. 二分查找的原理。 2. 二分查找的时间复杂度。 3. 其他查找算法(如线性查找)。 4. 在不同语言中实现二分查找。 确保相关问题的数量是4个。 完整回答结构: - 开头:回答问题。 - 解释:简要说明。 - 代码:提供二分查找的Python代码。 - 解释代码:描述算法。 - 相关问题:列出4个。 最终回答:</think>不,"find" 通常不是指二分查找(Binary Search)。在编程中,"find" 是一个通用的术语,可能指代多种查找操作,具体含义取决于上下文: - 在字符串操作中,`find()` 方法(如 Python 的 `str.find()`)通常执行线性查找(从开头扫描到结尾)。 - 在集合或数组中,`find()` 函数(如 C++ 的 `std::find()`)也通常是线性查找。 - 二分查找则是一种特定的高效算法,要求数据集必须已排序,并利用分治策略将时间复杂度降至 O(log n)。 为了更清晰地说明区别,我将提供一个二分查找的 Python 实现示例。二分查找的核心思想是:将有序数组分成两半,通过比较中间元素来缩小查找范围,直到找到目标或范围为空。 以下是一个标准的二分查找实现代码: ```python def binary_search(arr, target): """ 在有序数组 arr 中查找目标值 target 的索引。 如果找到,返回索引;否则返回 -1。 """ left, right = 0, len(arr) - 1 # 初始化左右指针 while left <= right: mid = (left + right) // 2 # 计算中间索引 if arr[mid] == target: return mid # 找到目标,返回索引 elif arr[mid] < target: left = mid + 1 # 目标在右半部分,调整左指针 else: right = mid - 1 # 目标在左半部分,调整右指针 return -1 # 未找到目标 # 示例使用 if __name__ == "__main__": sorted_array = [1, 3, 5, 7, 9, 11, 13] # 必须是有序数组 target_value = 7 result = binary_search(sorted_array, target_value) print(f"元素 {target_value} 的索引是: {result}") # 输出: 元素 7 的索引是: 3 ``` ### 代码解释: - **初始化指针**:`left` 和 `right` 分别指向数组的起始和结束索引。 - **循环条件**:`while left <= right` 确保查找范围有效(当左指针超过右指针时停止)。 - **计算中间索引**:`mid = (left + right) // 2` 使用整数除法找到中点。 - **比较与调整**: - 如果 `arr[mid] == target`,直接返回索引。 - 如果 `arr[mid] < target`,说明目标在右半部分,将 `left` 移到 `mid + 1`。 - 如果 `arr[mid] > target`,说明目标在左半部分,将 `right` 移到 `mid - 1`。 - **未找到处理**:循环结束后未找到,返回 -1。 - **时间复杂度**:O(log n),因为每次迭代都将搜索范围减半。 - **前提条件**:数组必须已排序(升序或降序),否则算法无效。 ### 为什么 "find" 不是二分查找? - "find" 通常不隐含排序要求,而二分查找强制要求数据有序。 - 标准库中的 `find()` 方法(如 Python 的字符串 `find()`)多是 O(n) 的线性查找,适用于未排序数据。 - 二分查找需要显式实现或调用特定函数(如 Python 的 `bisect` 模块)。 如果您有具体上下文(如某种语言的 "find" 函数),我可以进一步分析。
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值