C 查找矩阵NxN中的所有峰值

C 查找矩阵NxN中的所有峰值,c,algorithm,matrix,search,multidimensional-array,C,Algorithm,Matrix,Search,Multidimensional Array,我正在尝试创建一个算法,使用简单的方法查找nxn矩阵中的所有峰值。但是我在角落、第一行和最后一行以及第一列和最后一列方面遇到了一些问题。我考虑的问题如下: [ ][c][ ][ ] a is considered a 2d peak [d][a][e][ ] or a hill iff a >= b, [ ][b][ ][ ] a >= d, a >=c, a >=e [ ][ ][ ][ ] 然而,当我需要计算角点作为下面的表示时,c和d不存在。我必须评估太多的条件才

我正在尝试创建一个算法,使用简单的方法查找nxn矩阵中的所有峰值。但是我在角落、第一行和最后一行以及第一列和最后一列方面遇到了一些问题。我考虑的问题如下:

[ ][c][ ][ ] a is considered a 2d peak
[d][a][e][ ] or a hill iff a >= b,
[ ][b][ ][ ] a >= d, a >=c, a >=e
[ ][ ][ ][ ]
然而,当我需要计算角点作为下面的表示时,c和d不存在。我必须评估太多的条件才能得到更一般的结果。i、 e,对于下面的a吼叫,我需要检查a位置是否有效,如果
第1行<0
,那么我就不需要检查a上方的任何内容,如果col-1<0任何内容都在a的左侧

[a][e][ ][ ] 
[b][ ][ ][ ] 
[ ][ ][ ][ ] 
[ ][ ][ ][ ]
但是,当我们将a带到其他角落,或者甚至评估上述示例中的e等其他位置时,我需要证明e是否位于第1行存在的有效位置,以防止评估该位置并获得错误(在上面的例子中,如果
e>=第1行中的元素,我肯定会得到一个错误检查。我已经实现了一段代码,考虑了角点、第0行和第n行以及第0列和第n列,但是我停下来开始思考如何使它更具可读性和更简单

void find_hill(){
    int i, j;
    for(i = 0; i < n; i++){
        for(j = 0; j < n; j++){
            //check corners
            if(i-1 < 0){
                if(j-1 < 0){
                   //check if arr[i][j] >= arr at i,j+1 and i+1,j
                }
                if(j+1 > n-1){
                   //check if arr[i][j] >= arr at i,j-1 and i+1,j 
                }
            }                
        }
    }     
}
void find_hill(){
int i,j;
对于(i=0;i=i,j+1和i+1,j处的arr
}
如果(j+1>n-1){
//检查在i,j-1和i+1,j处的arr[i][j]>=arr
}
}                
}
}     
}

我想在这里讨论一下如何找到一个解决方案。我应该从哪里开始做一些简单的事情呢?我曾想过某种程度上使用类似于洪水填充的方法,但它分别填充每个位置,可能不会工作,因为我最终会遇到相同的问题!

这类似于将内核应用于图像,如Sobel过滤器或其他使用滑动窗口方法的过滤器。通常,我忽略边界,但当您想要检测矩阵边界上的山丘时,您需要识别窗口类型

如果你不关心内存拷贝,你可以在嵌套的内存中创建一个3x3窗口,如果窗口在一个角落里,用中心的值填充相应的值

int window[3][3];

for (int i = 0; i < n; ++i)
{
    for (int j = 0; j < n; ++j)
    {
        window[1][1] = arr[i][j];
        window[0][1] = (i - 1 < 0) ? window[1][1] : arr[i-1][j];
        window[2][1] = (i == n - 1) ? window[1][1] : arr[i+1][j];

        window[1][0] = (j - 1 < 0) ? window[1][1] : arr[i][j-1];
        window[1][2] = (j == n - 1) ? window[1][1] : arr[i][j+1];

        // Process window
        // ...
    }
}
int窗口[3][3];
对于(int i=0;i
我建议使用以下技巧:复制第一行和最后一行和列,如中所示:

[ ][a][b][c][ ]
[a][a][b][c][c]
[d][d][e][f][f]
[g][g][h][i][i]
[ ][g][h][i][ ]
然后让循环从1开始,在n-1结束。

void find\u hill(){
void find_hill() {

    int i, j, k, l;
    
    for(i = 0; i < n; i++){
    
        for(j = 0; j < n; j++){
        
            for(k = i-1; k <= i+1; k++) {
                
                for(l = j-1; l <= j+1; l++) {
                    
                    if( k > 0 && k < n && l > 0 && l < n && (i-k)*(j-l) == 0 && arr[i][j] >= arr[k][l] ) {
                        
                        arr[i][j] is a peak;
                    }
                }
            }                
        }
    }     
}
int i,j,k,l; 对于(i=0;i=arr[k][l]){ arr[i][j]是一个峰值; } } } } } }
你也可能有这种情况

if( !(k == i && j == l) && k > 0 && k < n && l > 0 && l < n && (i-k)*(j-l) == 0 && arr[i][j] > arr[k][l] )
if(!(k==i&j==l)和&k>0和&k0和&larr[k][l])
使用
!(k==i&&j==l)
可以避免在9次中运行其余条件1次,但增加了在9次中运行9次的权重


在这9次中的1次中,您也会在条件内执行代码,因此最好添加
!(k==i&&j==l)

在算法范围内,有几个选项

你可以增加矩阵的大小。从理论上讲,这是一个完全可以接受的选择,因为它只会随着矩阵的宽度成比例地增加内存量和计算量。但实际上,如果你使用相对较小的矩阵,它可能会将它们的大小增加到9倍(在1x1矩阵增加到3x3的情况下)。如果你发现这不雅观,你会发现很多东西不雅观,而避免这种不雅观的“解决方案”通常也比这些东西更不雅观和麻烦

另一个选择显然是循环中的条件语句。它在理论上是完美的,因为它根本不会增加内存,只会在你已经做过的每个循环周期中添加一个常量……实际上它确实做到了这一点,它使每个循环都需要额外的时间来检查一个条件语句,所以不管你是否在处理大量的小矩阵,或更小但更大的矩阵,使这段代码的性能更差。如果该代码曾经或很可能成为许多性能问题的瓶颈或生成器,那么这实际上是最糟糕的选择。如果不太可能是其中任何一个,那么这是一个很好的选择,因为它以明确和简洁的方式显示了您的意图因此,如果这是最好的选择,则取决于上下文,并且您可能会通过使用或不使用此解决方案在其他程序员中引起愤怒,这取决于这是他们只想快速阅读的代码的一部分,还是分析显示的对应用程序的低性能负有最大责任的部分

最后,您可以为所有特殊情况编写单独的代码部分-分别检查矩阵的四个角、四个边和其余部分。这不会导致“不必要”的内存使用,并会导致最快的代码工作。但与其他两个选项相比,读起来会很糟糕

也就是说,我不是在处理软件工程si