C++实现二维数组的二分查找

问题描述:
给定一个二维数组,其每行每列都已经按从小到大的顺序排列好了,要求设计一个高效的搜索算法。

思路:
有序、查找,这两个关键字一出现我们马上就会联想到二分查找,但是如何在二维数组(以下称之为矩阵)中进行二分查找呢?

根据题目描述,我们不难推断出这个矩阵的对角线上的元素也是有序排列的。

因此,我们可以先在矩阵的对角线上进行一维的二分查找,如果没有找到目标元素,就返回一个(最好是第一个)比目标元素大的元素。

这时候这个元素就将原矩阵分为了4个部分,其中右下角这个部分一定不包括目标元素(因为肯定比目标元素大),我们继续在剩余3个矩阵重复上述步骤即可。这个方法其实使用到了分治法的思想。

其中,当矩阵含有的元素个数为1时为最小子问题,直接判断即可。当然也可以适当扩大最小子问题的规模。

当然,实现算法的过程中比较复杂的地方是:如果矩阵行和列不相等,怎么确定对角线。我们可以采取比较模糊的方法:只要找到一个比目标元素大的元素即可!


1234
6789
10111213
14151617

例如上表中的矩阵,如果我们要寻找5的话,则首先定位到的元素应该是7(因为1、7,12、17中第一个比5大的元素为7),则7所在行和列包围的右下角子矩阵不可能存在目标元素,所以我们对下面3个子矩阵再进行上述步骤。


左下角子矩阵:

6
10
14

右上角子矩阵

234

左上角子矩阵

1

源代码:

//
//  main.cpp
//  SearchMatrix
//
//  Created by 胡昱 on 2021/11/18.
//

#include <iostream>
using namespace std;

// 类似于分治法
int search(int** matrix, int begin_x, int begin_y, int m, int n, int t) {
    // 处理极端情况
    if(matrix[begin_x][begin_y] > t || matrix[begin_x + m - 1][begin_y + n - 1] < t) {
        return 0;
    }
    // 处理最小子问题(也就是降低到一维的情况)
    if(m * n <= 1) {
        return (matrix[begin_x][begin_y]) == t ? 1 : 0;
    }
    // 处理一般情况
    int low = begin_x, high = begin_x + m - 1, m_mid = (low + high) / 2;
    int left = begin_y, right = begin_y + n - 1, n_mid = (left + right) / 2;
    // 根据类对角线上第一个大于目标元素的中间元素划分子问题(这两个值随便初始化了一下)
    int x_mid = begin_x, y_mid = begin_y;
    while(low <= high && left <= right) {
        if(matrix[m_mid][n_mid] == t) {
            return 1;
        }
        else if(matrix[m_mid][n_mid] < t) {
            if(low < high) {
                low = m_mid + 1;
            }
            if(left < right) {
                left = n_mid + 1;
            }
        }
        else {
            x_mid = m_mid;
            y_mid = n_mid;
            if(low < high) {
                high = m_mid - 1;
            }
            if(left < right) {
                right = n_mid - 1;
            }
        }
        int new_m_mid = (low + high) / 2;
        int new_n_mid = (left + right) / 2;
        if(new_m_mid == m_mid && new_n_mid == n_mid) {
            break;
        }
        else {
            m_mid = new_m_mid;
            n_mid = new_n_mid;
        }
    }
    // 求解子问题
    // 左上角结果 + 左下角结果 + 右上角结果
    int flag = 0;
    if(x_mid > begin_x && y_mid > begin_y) {
        flag += search(matrix, begin_x, begin_y, x_mid - begin_x, y_mid - begin_y, t);
    }
    if(x_mid <= begin_x + m - 1 && y_mid > begin_y) {
        flag += search(matrix, x_mid, begin_y, begin_x + m - x_mid, y_mid - begin_y, t);
    }
    if(x_mid > begin_x && y_mid <= begin_y + n - 1) {
        flag += search(matrix, begin_x, y_mid, x_mid - begin_x, begin_y + n - y_mid, t);
    }
    return flag;
}

int main(int argc, const char * argv[]) {
    // 共nums组测试
    int nums;
    cin >> nums;
    while((nums--) > 0) {
        // 输入矩阵和目标
        int m, n ,target;
        cin >> m >> n >> target;
        int** matrix = new int*[m];
        for(int mi = 0; mi < m; ++mi) {
            matrix[mi] = new int[n];
            for(int ni = 0; ni < n; ++ni) {
                cin >> matrix[mi][ni];
            }
        }
        
        // 开始二维的二分查找
        int flag = search(matrix, 0, 0, m, n, target);
        
        // 输出结果并清理资源
        cout << (flag > 0 ? "true" : "false") << endl;
        for(int mi = 0; mi < m; ++mi) {
            delete [] matrix[mi];
        }
        delete [] matrix;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值