本文由于测试是选取的测试集不具有一般性,得到的结论是错的(后续抽时间更正实验),但讨论的过程,也许可以给你带来些思考(建议直接看结论)。
主要思路在于探讨所要查找的数位于原数组元素之间或者上下限之外(如原数组[1, 3, 5, 6], 要找0, 4, 10)时 l,r指针的情况。
left = 0, r = v. size() - 1, while(l <= r)时
void test() {
vector<int> v{1, 3, 5, 7, 9, 11, 13, 15, 17};
vector<int> vl, vr, vm;
int find_val;
//输入要查询的值,看二分搜索下标的情况
while(cin >> find_val) {
int l = 0, r = v.size() - 1, mid;
while(l <= r) {
vl.push_back(l); // 前面加tab的三行,用于后面打印
vr.push_back(r);
mid = l + ((r-l)>>1);
vm.push_back(mid);
if(v[mid] == find_val) break;
if(v[mid] > find_val) r = mid-1;
else l = mid+1;
}
//分别输出mid, l, r的运行过程中所有下标
//要找的值
cout << "f: " << find_val;
//l下标
cout << endl << "l: ";
for(int i : vl)
cout << i << " ";
cout << l;
//r下标
cout << endl << "r: ";
for(int i : vr)
cout << i << " ";
cout << r;
//mid下标
cout << endl << "m: ";
for(int i : vm)
cout << i << " ";
cout << mid << endl;
vl.clear(), vr.clear(), vm.clear();
}
}
几组测试数据:
//left = 0, r = v.size() - 1, while(l <= r)
//v为要找的值,mid为下标中值,l为左下标,r为右下标
//最后一列下标值为出循环后的各下标值
//v[] = {1, 3, 5, 7, 9, 11, 13, 15, 17} 待查询数组长度为9,下标范围(0 ~ 8)
-1
f: -1
l: 0 0 0 0
r: 8 3 0 -1
m: 4 1 0 0
1
f: 1
l: 0 0 0 0
r: 8 3 0 0
m: 4 1 0 0
5
f: 5
l: 0 0 2 2
r: 8 3 3 3
m: 4 1 2 2
6
f: 6
l: 0 0 2 3 3
r: 8 3 3 3 2
m: 4 1 2 3 3
7
f: 7
l: 0 0 2 3 3
r: 8 3 3 3 3
m: 4 1 2 3 3
19
f: 19
l: 0 5 7 8 9
r: 8 8 8 8 8
m: 4 6 7 8 8
小结:
编码方式:left = 0, r = v.size() - 1, while(l <= r)
找到时:
find_val = 1(0), 7(3) 【圆括号内为下标值,用于观察下标奇偶性】
find_val的下标值:l = r = mid
find_val = 5(2)
find_val的下标值:l = mid ≠ r
所以找到 find_val 时,正确表示下标的是 l
未找到时:
当要find_val = -1小于所有的数时,r体现出未找到,且 l > r
当find_val = 19大于所有数时,l体现出未找到,且 l > r
当find_val = 6在所有数的之间却不是其中一个时,l > r
所以未找到 find_val 时,总有 l > r
换个角度:
从while(l <= r)代码块的出口这个角度来分析较简单,执行完这个代码块后,只有两种可能,要么是 l > r,要么是从mid处break: mid = (l+r)/2,r = l 或 l+1;
left = 0, r = v. size() , while(l < r)时
只需对上面代码做微调
void test() {
vector<int> v{1, 3, 5, 7, 9, 11, 13, 15, 17};
vector<int> vl, vr, vm;
int find_val;
//输入要查询的值,看二分搜索下标的情况
while(cin >> find_val) {
int l = 0, r = v.size(), mid;
while(l < r) {
vl.push_back(l); // 前面加tab的三行用于后面打印
vr.push_back(r);
mid = l + ((r-l)>>1);
vm.push_back(mid);
if(v[mid] == find_val) break;
if(v[mid] > find_val) r = mid-1;
else l = mid+1;
}
//分别输出mid, l, r的运行过程中所有下标
//要找的值
cout << "f: " << find_val;
//l下标
cout << endl << "l: ";
for(int i : vl)
cout << i << " ";
cout << l;
//r下标
cout << endl << "r: ";
for(int i : vr)
cout << i << " ";
cout << r;
//mid下标
cout << endl << "m: ";
for(int i : vm)
cout << i << " ";
cout << mid << endl;
}
}
几组测试数据:
//left = 0, r = v.size(), while(l < r)
//v为要找的值,mid为下标中值,l为左下标,r为右下标
//最后一列下标值为出循环后的各下标值
//v[] = {1, 3, 5, 7, 9, 11, 13, 15, 17} 待查询数组长度为9,下标范围(0 ~ 8)
-1
f: -1
l: 0 0 0
r: 9 3 0
m: 4 1 1
1
f: 1
l: 0 0 0
r: 9 3 0
m: 4 1 1
5
f: 5
l: 0 0 2 2
r: 9 3 3 3
m: 4 1 2 2
6
f: 6
l: 0 0 2 3
r: 9 3 3 3
m: 4 1 2 2
7
f: 7
l: 0 0 2 3
r: 9 3 3 3
m: 4 1 2 2
9
f: 9
l: 0 0
r: 9 9
m: 4 4
19
f: 19
l: 0 5 8 9
r: 9 9 9 9
m: 4 7 8 8
小结:
编码方式:left = 0, r = v.size(), while(l < r)
找到时:
find_val = 1(0), 5(2) 【圆括号内为下标值,用于观察下标奇偶性】
find_val的下标值:l = mid ≠ r
find_val = 7 (3)
find_val的下标值:l = r ≠ mid
find_val = 9(4)
find_val的下标值:mid ≠ l ≠ r
所以找到 find_val 时,正确表示下标的是 l 或 mid
未找到时:
当要find_val = -1 小于所有的数时,l = r, v[l] != find_val
当find_val = 19 大于所有数时,l = r, v[l] != find_val
当find_val = 6 在所有数的之间却不是其中一个时,l = r, v[l] != find_val
所以未找到 find_val 时,总有 l = r 且 v[l] != find_val
换个角度:
从while(l < r)代码块的出口这个角度来分析较简单,执行完这个代码块后,只有两种可能,要么是 l = r,要么是从mid处break: l <= r;