我正在研究二进制搜索算法,我已经多次看到编写如下的算法(这是C ++,但语言在这里并不重要):
int start = 0;
int end = vec.size() - 1;
do {
int mid = (lo + hi) / 2;
if (target < vec[mid])
start = mid + 1;
else if (target > vec[mid])
end = mid - 1;
else
// found
} while (start <= end);
但是我也看到过这样的实现:
int start = 0;
int end = vec.size() - 1;
do {
int mid = (int)ceil((lo + hi) / 2.0);
if (target < vec[mid])
start = mid + 1;
else if (target > vec[mid])
end = mid - 1;
else
// found
} while (start <= end);
两者似乎都有效。是否有正确性或性能原因我应该获取ceil
并执行第二种情况浮点运算而不是使用第一个版本?
答案 0 :(得分:2)
int mid = (lo + hi) / 2
时:
当[left,right]之间的数组大小为奇数时,你通过取两个潜在中间元素的左元素决定mid
元素,即对于数组[4,5],你的mid将是4。因此,如果没有任何ceil
floor
,则除法的工作方式与floor
非常相似。
(int)ceil((lo + hi) / 2.0);
时:
当[left,right]之间的数组大小为奇数时,你通过取两个潜在中间元素的正确元素决定mid
元素,即[4,5]你的mid将是5。 / p>
因此,这两个选项都会有效,因为您根据某些有效条件(target < vec[mid]
和target > vec[mid]
)放弃/获取某个部分,分区点在这里很重要
另一件事是,在int mid = (lo + hi) / 2
等操作期间,如果求和超出整数范围,则在添加lo
和hi
时可能会遇到溢出。如此安全就是写mid = lo + (hi - lo) / 2
,这将产生相同的输出。
希望它有所帮助!
所以两者之所以有效,只是因为我从新的元素中丢弃了mid元素 重启搜索时的搜索范围,对吧?
是。如果你不放弃mid
元素,它将落入无限循环,即[4,5],4将始终被选为mid
,而对于left = mid
这样的调用,它会创造一个无限循环。