给定一个二维数组,数组的特点是:每一行从左到右数据大小依次递增,每一列数据从上到下依次递增,要求判断一个整数是否在这个二维数组中;

设计二维数组如下:

wKioL1cfMmLxgqRwAAAY1Yn6gfs969.png


    首先,毋庸置疑的的是,遍历一遍数组肯定能判断出来,这也是最笨的方法了,因此,要想提高程序的运行效率就得找出一种高效的方法来查找;

    一开始的想法大概都能想到从数组第一行第一列的数开始沿着对角线判断,如果是对角线数据就可以直接返回,比如我们要想查找17这个数,这时候170、9、16都要大,因此以0、9、16为对角线的矩形数据就可以排除了,接下来判断21发现比17大要停下来,因此17这个数就卡在比16大但是比21小的范围内,但是这个范围可画如下图:

wKiom1cfOqaCNt4MAAAWK8Hh_nY360.png

如图上所示,白色区域内的数据都可以排除,但是满足目前为止的判断条件的数据都是×××区域内的数据,由于上面给出的数组是给定死了的,但实际上确实是×××区域内的数据都可能满足条件;

    然后呢?然后就卡住了......这样也就是不好再往下执行了,因此这种思路会阻塞,可以换一种思路重新开始判断;


    首先,可以从数组的右上角开始判断,试想,如果要查找的数比右上角的数要小的话,那么右上角所在的那一列都可以被排除了,当然如果等于右上角的话就直接返回了,而如果要查找的数比右上角的数要大的话,那么右上角所在的那一行都可以排除了,当判断之后所排除的那一行或者那一列不在考虑范围之内了之后,再次寻找剩下的右上角的数据,依次循环判断,直到行从0变到最大值,列从最大值变为0为止;

代码可实现如下:

#include <iostream>
#include <assert.h>
using namespace std;

bool SearchNum(int (*parr)[5], size_t row, size_t col, int num)
{
    assert(parr);
    size_t tmp_row = 0;
    size_t tmp_col = col-1;

    while((tmp_row < row) && (tmp_col >= 0)) 
    {   
        if(parr[tmp_row][tmp_col] == num)
            return true;
        else if(parr[tmp_row][tmp_col] > num)
            --tmp_col;
        else
            ++tmp_row;
    }   
    return false;
}

int main()
{
    int arr[5][5] = {{0,  1,  2,  3,  4}, 

                     {5,  9, 10, 11, 12},

                     {6, 13, 16, 17, 18},

                     {7, 14, 19, 21, 24},

                     {8, 15, 22, 23, 25}};

    bool ret = SearchNum(arr, 5, 5, 17);  //success return true, failed return false
    if(ret)
        cout<<"the num is exist..."<<endl;
    else
        cout<<"the num is not exist..."<<endl;
    return 0;
}

当要查找的数为17的时候,运行程序结果如下:

wKioL1cfPz_x_2UJAAAFcMgV8No748.png


当将要查找的数字改为20的时候,程序运行如下:

wKiom1cfPnbDWWX4AAAFbUtybMc809.png



《完》