二分查找详解
二分查找
介绍
关于二分查找,也叫折半查找,顾名思义,就是把数据分成两半,将目标值和中间值进行比较,然后决定舍弃左还是右,之后继续缩小范围,但是它有个前提>> 必须是有序 \color{red}{必须是有序} 必须是有序。思路就是这样,一开始以为懂了,但是最后有时写的时候,却发现出现了问题,这是细节没有把握住,没有真正注意到。现在我来说说我的理解,希望能对你有所帮助。
我认为里面最重要的是:
while的循环条件
边界的控制
条件控制
以left和right为边界来说循环条件一般是:
left<=right
left< right
而边界的控制则是每次折半后
l
e
f
t
和
r
i
g
h
t
的取值
\color{red}{left和right的取值}
left和right的取值。
中间值大于目标值时,目标值在左区间,这时左区间的右边界范围就有不同了
分别是:
right=middle-1
right=middle
- 两个区间不同的就是有没有将中间middle给算进去,而这两个区间搭配两个不同的循环条件,结果 可能会有所不同。当初我学二分时也是大致的看看了,对于right的取值也是不太明白,直到后面出现错误才回头仔细看。
while(left<=right)
>>right=middle-1(正确做法)
int search(int nums[], int size, int target)
{
int left = 0;
int right = size - 1;
while (left <= right) { //当left == right时
int middle = (left + right) /2;
if (nums[middle] > target) {
right = middle - 1; //target在左区间,所以[left, middle - 1]
} else if (nums[middle] < target) {
left = middle + 1; //target在右区间,所以[middle + 1, right]
} else { //相等时
return middle;
}
}
//没有找到目标值
return -1;
}
>>right=middle(错误做法)
int search(int nums[], int size, int target)
{
int left = 0;
int right = size-1;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle; //
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
// 没找到就返回-1
return -1;
}
>>图文解释
我们就来看错误的情况的吧:
r
i
g
h
t
=
m
i
d
d
l
e
\color{red}{right=middle}
right=middle
假设找81这个数
while(left<right)
>>right=middle(正确写法)
int search(int nums[], int size, int target)
{
int left = 0;
int right = size-1;
while (left < right) { //因为left = right的时候,在[left, right)区间上无意义
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle; //target 在左区间,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
// 没找到就返回-1
return -1;
}
>>right=middle-1(错误做法)
int search(int nums[], int size, int target)
{
int left = 0;
int right = size-1;
while (left < right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle-1; //修改为这个就出问题了
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
// 没找到就返回-1
return -1;
}
图文解释
r
i
g
h
t
=
m
i
d
d
l
e
−
1
\color{red}{right=middle-1}
right=middle−1
这次的错误是判断条件导致的,可能找的那个数正是left==right时,而此时,却被迫跳出循环,导致错过了要找的数,我们找51试试
(7是返回的下标,也就是51的下标),实际上直接出去了,返回了-1
总结
对于二分,还有一个,我之前看到,对于它们是左右区间是开还是闭,统一直接用闭区间更加方便,right的初始值就给数组最后一个的下标就行了,这样更容易些,因此我们可以把正确的记下来,我画了个图,来帮助大家记忆
left保持不动
while和right
要少一起少(少了
=
和
−
1
),要多一起多(多了
=
和
−
1
)
\color{red}{要少一起少(少了=和-1),要多一起多(多了=和-1)}
要少一起少(少了=和−1),要多一起多(多了=和−1)。
好了,今天就到这里,希望这些能够帮助你们,共同进步!