题目来自剑指offer
题目:
思路:
根据指针low,mid,high三个指针指向元素的大小确定二分往左走还是往右走
如果arr[low] <= arr[mid]:则区间[low,mid]的元素是递增的,有升有降应该在右边区间,应该往右走
如果arr[low] > arr[mid]: 则区间[low,mid]的元素是有递增有递减,则应该往左走
终止条件:
区间只剩两个元素时,终止。此时该区间肯定值一个大一个小(high指向),此时返回high指向元素即可
注意:
有一种情况解决不了。
在arr[low] = arr[mid] = arr[high]时,此时无法确定之后处理左区间还是右区间。此时只能对该区间直接顺序遍历找到最小数
举例:
当数组元素为 1 0 1 1 1 和 1 1 1 0 1,上述思路无法同时处理这两种情况。
即上述思路,要求low,mid,high三个指针指向的三个元素至少有一个元素是不同的。
代码:
不完全正确的代码:
int BinSearch(int nArr[],int nStart,int nEnd) { assert(nArr != NULL && nStart >= 0 && nEnd >= nStart); int nLow = nStart; int nHigh = nEnd; int nMid = -1; while (nLow + 1 < nHigh) { nMid = (nLow + nHigh)/2; if (nArr[nLow] <= nArr[nMid])//向右走 { nLow = nMid; } else //向右走 { nHigh = nMid; } } //终止时,有指针nLow和nHigh相邻,指向的两个元素肯定是一升一降,nLow指向大元素,nHigh指向小元素 assert(nHigh >= nStart && nHigh <= nEnd); return nArr[nHigh]; }
正确代码:
int BinSearch(int nArr[],int nStart,int nEnd) { assert(nArr != NULL && nStart >= 0 && nEnd >= nStart); int nLow = nStart; int nHigh = nEnd; int nMid = -1; while (nLow + 1 < nHigh) { nMid = (nLow + nHigh)/2; if (nArr[nLow] == nArr[nMid] && nArr[nMid] == nArr[nHigh]) { //不能区分往左走还是往右走,此时要顺序查找 int nMin = 0x3f3f3f3f; for (int i = nLow;i <= nHigh;i++) { if (nMin > nArr[i]) { nMin = nArr[i]; } } return nMin; } if (nArr[nLow] <= nArr[nMid])//向右走 { nLow = nMid; } else //向右走 { nHigh = nMid; } } //终止时,有指针nLow和nHigh相邻,指向的两个元素肯定是一升一降,nLow指向大元素,nHigh指向小元素 assert(nHigh >= nStart && nHigh <= nEnd); return nArr[nHigh]; }测试代码:
#include <iostream> #include <assert.h> using namespace std; int BinSearch(int nArr[],int nStart,int nEnd) { assert(nArr != NULL && nStart >= 0 && nEnd >= nStart); int nLow = nStart; int nHigh = nEnd; int nMid = -1; while (nLow + 1 < nHigh) { nMid = (nLow + nHigh)/2; if (nArr[nLow] == nArr[nMid] && nArr[nMid] == nArr[nHigh]) { //不能区分往左走还是往右走,此时要顺序查找 int nMin = 0x3f3f3f3f; for (int i = nLow;i <= nHigh;i++) { if (nMin > nArr[i]) { nMin = nArr[i]; } } return nMin; } if (nArr[nLow] <= nArr[nMid])//向右走 { nLow = nMid; } else //向右走 { nHigh = nMid; } } //终止时,有指针nLow和nHigh相邻,指向的两个元素肯定是一升一降,nLow指向大元素,nHigh指向小元素 assert(nHigh >= nStart && nHigh <= nEnd); return nArr[nHigh]; } int main() { //int nArr[5] = {3,4,5,1,2}; //int nArr[5] = {3,1,2,3,4}; //int nArr[5] = {3,1,1,1,1}; //int nArr[5] = {3,3,3,3,1}; //int nArr[5] = {1,1,1,1,1}; //int nArr[5] = {1,0,1,1,1}; int nArr[5] = {1,1,1,0,1}; cout<<BinSearch(nArr,0,4)<<endl; system("pause"); return 1; }