二分查找的一些细节问题
- 更多内容可见二分查找细节详解。
- 首先就是mid的赋值应该写为mid= left+(right-left)/2,这里是为了避免越界。
并且mid不一定恒为此种写法,因为对于整型计算,1/100是为0的,原因就在于两个int型数据相除其不会四舍五入,即小数部分会被直接去掉,所以这里有可能会陷入一种死循环状态,即mid的值永远不会改变。 - 这种异常状态在正常的二分查找是不会出现问题的,即:
while(left<=right)
{
mid = left+(right-left)/2;
if(res[mid]>target)
{
right = mid-1;
}
if(res[mid]<target)
{
left = mid+1;
}
if(res[mid]==target)
{
return 1;
}
}
-
正常二分是查找到mid对应元素后立刻return,因此这里即返回的过程是在循环内完成的!!而如果不是left<=right,而是left<right,则最后一次由于区间缩小到了left==right,此时由于没加等号直接退出循环,我们发现此时对应的mid刚好就是left与right相加除以2的结果,即此时该输出的,但是我们让他退出循环了,所以没有成功return,所以这里需要加等号,即left<=right,限制了那种情况下最后一次在循环体内进行return.
-
但是对于另一种二分查找,即查找的不是target,而是刚好小于target的:
while(left<right)
{
mid = left+(right-left)/2;
if(letters[mid]>target)
{
right = mid;
}
else if(letters[mid]<=target)
{
left = mid+1;
}
}
-
由上述可知,这里由于查找到满足的mid后还要进行验证,因为他不一定是“刚好小于target”,因此我们这里即使查找到了也是当成没有查找到,一直进行循环,直到程序结束,再输出我们最终验证成功的那个。也就是说我们是把找到后输出的过程放在了循环外面,而最后找到后即此时对应left==right,有了此标志后我们已经能判断出此时已经“找到了”,所以直接退出循环返回right或left任意一个即可;
-
而你若将循环判断条件改为left<=right,则最后找到了的情况还要进行一次循环,这里的话会使得left变了,并没有让left和right都改变,因此这样也是可以的但是最后输出的话必须输出的是right了。
-
我们发现其与正常二分有些许不同,但是mid的赋值是不变的。 但是当我们要查找刚好比target大的元素时:
while(left<right)
{
mid = left+(right-left+1)/2;//不多搞1则会卡住
if(matrix[mid][0]>target)
{
right = mid-1;
}
if(matrix[mid][0]<=target)
{
left = mid;
}
}
- 我们发现mid的赋值发生了变化,这是因为当left = 0,right =
3时,循环一次后由于计算机不会四舍五入导致数值出现误差,以至于mid的值保持不变,而mid不变由于查找的条件,得到left=mid,所以此时陷入了一个恒等式中,即死循环中,所以要加1.(如果加0.5也是不行的,因为都是整型变量,所以最少要加1)。