在c ++中不同行或列旁边的矩阵中搜索最小值和最大值的最快方法是啥

Posted

技术标签:

【中文标题】在c ++中不同行或列旁边的矩阵中搜索最小值和最大值的最快方法是啥【英文标题】:what is the fastest way to search inside a matrix for min and max alongside of different rows or cols in c++在c ++中不同行或列旁边的矩阵中搜索最小值和最大值的最快方法是什么 【发布时间】:2015-04-15 15:24:22 【问题描述】:

假设我需要在矩阵中搜索行和列以找到最小值,最好的方法是什么?

目前我能想到的是有两个嵌套向量如下:

std::vector<std::vector<float>> myData;

并以这种方式搜索它:

// row search on row say 10
int index= std::min_element(myData[10].begin(), myData[10].end()) - myData[10].begin();

但是为了在 cols 上搜索,我需要编写一个 for 循环来进行搜索。

 // col search say on col 20
 float min_value=10000000;  / assuming values in table are less than this value
 int min_index=-1;
 for(int i=0;i<myData.size();++i)
 
       if(myData[i][20] <min_value)
       
            min_value=myData[i][20];
            min_index=i;
        
  

有没有更好的方法来做到这一点?我也可以访问 OpenCV。

【问题讨论】:

你的矩阵是动态变化的还是静态的? 我想计算最小值时知道大小,但编译期间不知道大小。 最快的方法是将矩阵分配为一个连续的向量并按顺序对其进行迭代。如果在施工时尺寸是固定的,那就是这样做的。 @Alex 这会给我全局最小值,但我需要每行或每列旁边的最小值。 我的意思是值会动态变化 【参考方案1】:

由于结构中的元素将发生变化,最好的选择是使用 binary index trees(又名 Fenwick 树)实现 Range 最小查询(RMQ)。我建议您为每一行和每一列保留一棵这样的树。如果要支持对原始矩阵的子矩阵的查询,还可以实现此类树的树。我提出的解决方案将需要O(N * M ) 额外的内存,其中 N 和 M 是矩阵的维度。它还将支持复杂的查询和更新O(log(N) + log(M))

【讨论】:

谢谢,有没有使用 cv::Mat 且易于使用和实现的解决方案? 我不知道这样的解决方案,我从未使用过 cv::Mat【参考方案2】:

如果你有 OpenCV Mat,你可以使用minMaxLoc:

void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, 
    Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())

返回值minVal/maxVal 包含实际值,而minLoc/maxLoc 是最小值/最大值的坐标(如果有多个,则第一次出现)。

显然,如果您传递整个矩阵,您将获得全局最小值/最大值,但您也可以只传递单个行或列。

对于矩阵C,您可以使用Mat::col 找到列n 的最小值/最大值

minMaxLoc(C.col(n), &minVal, &maxVal, &minLoc, &maxLoc);

或者对于行m 使用Mat::row

minMaxLoc(C.row(m), &minVal, &maxVal, &minLoc, &maxLoc);

Mat::colMat::row 都是 O(1) 操作,因为它们不复制任何数据,但我还没有进行任何基准测试来确定它们的列迭代速度。

【讨论】:

这给出了整个矩阵的最小值/最大值,但我对特定行/列旁边的最小值/最大值感兴趣。 抱歉,我不明白您在这种情况下使用“旁边”这个词。 好的,在阅读了其他一些答案后,您似乎正在寻找给定行或列的最小值/最大值。我会更新我的答案。【参考方案3】:

我们可以将cv::reduce(1) 用于行/列最小/最大值,而不是使用minMaxLoc 和range/roi。示例如下。

unsigned char data[4][2] =  1,2,3,4,5,6,7,8 ;
Mat img(4, 2, CV_8UC1, data) ;

Mat rowMinImg;
int singleCoumnResult = 1;
cv::reduce(img, rowMinImg, singleCoumnResult, CV_REDUCE_MIN );

//Mat colMinImg;
//int singleRowResult = 0;
//cv::reduce(img, colMinImg, singleRowResult, CV_REDUCE_MIN );

快速浏览一下 cv::reduce(2) 的实现,发现它是一个简单的 for 循环来查找最小值/最大值。所以,如果你的数据已经在 OpenCV Mat 中,我认为这是要走的路。

【讨论】:

【参考方案4】:

虽然这可能比您想要的更复杂,但可以将iterator base class 子类化。那里有一个简单的例子。您将重新定义运算符以遍历列。这样,您可以像行迭代器一样将它们传递给 min_element。

【讨论】:

【参考方案5】:

如果我理解正确,您希望能够找到给定矩阵的最小值和最大值(和位置):

    全球 在单行中,并且, 在单列中

那么下面的MWE 可能会对你有所帮助。我们先看输出:

mat = 
[75, 97, 66, 95, 15, 22;
 24, 21, 71, 72, 34, 66;
 21, 69, 88, 72, 64, 1;
 26, 47, 26, 40, 95, 24;
 70, 37, 9, 83, 16, 83]

global min =   1 @ [5, 2]
global max =  97 @ [1, 0]

Row 0 min =  15 @ [4, 0] max =  97 @ [1, 0]
Row 1 min =  21 @ [1, 1] max =  72 @ [3, 1]
Row 2 min =   1 @ [5, 2] max =  88 @ [2, 2]
Row 3 min =  24 @ [5, 3] max =  95 @ [4, 3]
Row 4 min =   9 @ [2, 4] max =  83 @ [3, 4]

Col 0 min =  21 @ [0, 2] max =  75 @ [0, 0]
Col 1 min =  21 @ [1, 1] max =  97 @ [1, 0]
Col 2 min =   9 @ [2, 4] max =  88 @ [2, 2]
Col 3 min =  40 @ [3, 3] max =  95 @ [3, 0]
Col 4 min =  15 @ [4, 0] max =  95 @ [4, 3]
Col 5 min =   1 @ [5, 2] max =  83 @ [5, 4]

以及对应的代码(你说的可以用OpenCV):

#include <opencv2/core/core.hpp>

#include <algorithm>
#include <iostream>
#include <iomanip>

namespace 

template <typename T>
std::pair< cv::Point, cv::Point > findMinMaxLoc( cv::Mat_<T> & mat )

    double ignored1, ignored2;
    std::pair< cv::Point, cv::Point > mmloc;
    cv::minMaxLoc( mat, &ignored1, &ignored2, &(mmloc.first), &(mmloc.second) );

    return mmloc;


template <typename T>
std::pair< cv::Point, cv::Point > minMaxLocRow( cv::Mat_<T> & mat, int row )

    cv::Rect roi( 0, row, mat.size().width, 1 );
    cv::Mat_<T> matRow = mat( roi );

    std::pair< cv::Point, cv::Point > mmloc = findMinMaxLoc( matRow );
    mmloc.first.y  = row;
    mmloc.second.y = row;

    return mmloc;


template <typename T>
std::pair< cv::Point, cv::Point > minMaxLocCol( cv::Mat_<T> & mat, int col )

    cv::Rect roi( col, 0, 1, mat.size().height  );
    cv::Mat_<T> matCol = mat( roi );

    std::pair< cv::Point, cv::Point > mmloc = findMinMaxLoc( matCol );
    mmloc.first.x  = col;
    mmloc.second.x = col;

    return mmloc;


 // namespace

int main( int argc, char ** argv )

    // Generate a matrix filled with random data.
    cv::Size size( 6, 5 );
    cv::Mat1i mat( size ); // Or cv::Mat1b, cv::Mat3f, etc.
    cv::RNG rng( cv::getCPUTickCount() );

    rng.fill( mat, cv::RNG::UNIFORM, 0, 100 );

    std::cout << "mat = " << std::endl << mat << std::endl << std::endl;

    // Find the global minimum and maximum.
    std::pair< cv::Point, cv::Point > mmloc = findMinMaxLoc( mat );

    std::cout << "global min = " << std::setw( 3 ) << std::setfill( ' ' );
    std::cout << mat( mmloc.first )  << " @ " << mmloc.first  << std::endl;
    std::cout << "global max = " << std::setw( 3 ) << std::setfill( ' ' );
    std::cout << mat( mmloc.second ) << " @ " << mmloc.second << std::endl << std::endl;

    // Row-wise extrema.
    for ( int row = 0; row < size.height; ++row )
    
        std::pair< cv::Point, cv::Point > mmloc = minMaxLocRow( mat, row );

        std::cout << "Row " << row;
        std::cout << " min = " << std::setw( 3 ) << std::setfill( ' ' );
        std::cout << mat( mmloc.first )  << " @ " << mmloc.first;
        std::cout << " max = " << std::setw( 3 ) << std::setfill( ' ' );
        std::cout << mat( mmloc.second ) << " @ " << mmloc.second << std::endl;
    
    std::cout << std::endl;

    // Column-wise extrema.
    for ( int col = 0; col < size.width; ++col )
    
        std::pair< cv::Point, cv::Point > mmloc = minMaxLocCol( mat, col );

        std::cout << "Col " << col;
        std::cout << " min = " << std::setw( 3 ) << std::setfill( ' ' );
        std::cout << mat( mmloc.first )  << " @ " << mmloc.first;
        std::cout << " max = " << std::setw( 3 ) << std::setfill( ' ' );
        std::cout << mat( mmloc.second ) << " @ " << mmloc.second << std::endl;
    

    return 0;

也许我提出的解决方案不是最佳方式(您明确要求),但它是一个简单的解决方案。

【讨论】:

以上是关于在c ++中不同行或列旁边的矩阵中搜索最小值和最大值的最快方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

给定字符串中的混合重音字符和普通字符在搜索时在 java 中不起作用

Ex 7_17 考虑如下的网络(其中数字为对应边的容量)...第十三次作业

ZZNUOJ_用C语言编写程序实现1154:二分搜索(附完整源码)

一般图匹配

为啥 JL 命令在我的汇编代码中不起作用?

在一个listview中嵌套ListView可以吗?