写好一段正确并且完整的二分查找也不容易

昨天去有道二面,在一个关键词搜索纠错的设计题后,来了一道程序题。是循环数组的二分查找。当时,因为前面扯的时间较长,而面试时间固定在一个小时到一个小时十五分之间,面试官说大致如此就没让我写全。后来自己回到宿舍写了下,发现竟然还是蛮搞的。尤其是刚开始思路没理清楚去做事情的时候,反反复复,甚是烦人。所以写此篇,以作警示。

题目: A是有序数组,B是将A斩断后调换前后顺序的数组(也就是像右循环移动了k个元素)。给出一个元素e,问如何高效的寻找这个e是不是在数组B中。

思路:循环数组+二分查找

 

解答过程:

1. 循环数组,无非real index和logic index,logic index = (real index – k + len )%len.

2. 如何正确的写一个二分查找

下面的函数是很通用的一个二分查找的过程,但如果把logic index的方法直接用到下面这个函数上会有边界的问题。例如r = 0时候,l=0,那么如果给r-1的时候,就会得到r=(r-1+len)/len = len-1一下子跳到了最右边的位置,所以l<r依旧成立,这样会死循环。

bool normal_bs(int *a, int k, int s, int arrlen){
int l = 0, r = (arrlen-1), m;
while((l) < (r)){
m = ((l)+(r))>>1;
if( a[m] == s ){
return true;
}else if( s > a[m]){
l = (m+1);
}else if( s < a[m]){
r = (m-1);
}
}
return false;
}

一个较好的二分查找的程序,一般二分停止条件是l与r发生了位置交换,而发生位置交换前,l==r的情形一定会出现的。所以只需要如下的做:

bool normal_bs(int *a, int k, int s, int arrlen){
int l = 0, r = (arrlen-1), m;
while(true){

if( l==r ){ // 循环停止条件

if(a[l] == s) return true;

else return false;

}
m = ((l)+(r))>>1;
if( a[m] == s ){
return true;
}else if( s > a[m]){
l = (m+1);
}else if( s < a[m]){
r = (m-1);
}
}
return false;
}

个人觉得这个写法是较之于之前写法更优的一个写法。

一下是循环数组+二分查找的示例。要加强自己的努力啊,太弱了。呵呵~

//============================================================================
// Name        : binarySearch.cpp
// Author      : jry
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;
bool NAIVE_DEBUG = false;

bool find(int *a, int k, int s, int arrlen){

    int l = (0+k)%arrlen, r = (arrlen-1+k)%arrlen, m;
    while(true){
        if( NAIVE_DEBUG ) cout << a[l] << "," << a[r] << endl;
        if( l == r ) {
            if( a[l] == s ) return true;
            else return false;
        }

        //the middle element.
        m = ((l-k+arrlen)%arrlen + (r-k+arrlen)%arrlen)>>1; // logic index
        m = (m+k)%arrlen; // physical index

        if( a[m] == s ){
            return true;
        }else if( a[m] < s ){
            l = (m+1+arrlen)%arrlen;
        }else if( a[m] > s ){
            r = (m-1+arrlen)%arrlen;
        }
    }
    return false;
}

bool normal_bs(int *a, int k, int s, int arrlen){
        int l = 0, r = (arrlen-1), m;
        while((l) < (r)){
            m = ((l)+(r))>>1;
            if( a[m] == s ){
                return true;
            }else if( s > a[m]){
                l = (m+1);
            }else if( s < a[m]){
                r = (m-1);
            }
        }
        return false;
}

int main() {

    int a[] = {4, 5, 6, 7, 8, 1, 2, 3, 4}, k = 5;
    int b[] = {6, 0, 6, -11110, 3, 1, 10}, len  = sizeof(a)/sizeof(int);
    for( int i = 0; i < (int)(sizeof(b)/sizeof(int)); i ++){
        if(find(a, k, b[i], len))
            cout << b[i] << " in array." << endl;
        else
            cout << b[i] << " not in array." << endl;
    }
    cout << "!!!DONE!!!" << endl; // prints !!!Hello World!!!
    return 0;
}

posted on 2011-09-29 12:18  amojry  阅读(549)  评论(0编辑  收藏  举报