二维阵列峰值查找器的问题

Issues with 2D array peaks finder

我在教程的帮助下编写了这段代码,代码工作正常但它没有输出我应该得到的答案,它给我的答案是 (2,4) 和 (3,3)是 5530 和 5411,而我应该得到 (2,1)、(2,5) 和 (4,3),它们是 5560、5821 和 5831。代码应该只输出这 3 个值

代码如下

#include <stdio.h>

#define columns 7
#define rows 6

int arr[rows][columns] = {
   { 5039,  5127,  5238,  5259,  5248,  5310,  5299 },
   { 5150,  5392,  5410,  5401,  5320,  5820,  5321 },
   { 5290,  5560,  5490,  5421,  5530,  5831,  5210 },
   { 5110,  5429,  5430,  5411,  5459,  5630,  5319 },
   { 4920,  5129,  4921,  5821,  4722,  4921,  5129 },
   { 5023,  5129,  4822,  4872,  4794,  4862,  4245 },
};

void find_peaks(int arr[][columns]);

int main() {
    
    find_peaks(arr);

    return 0;
}

void find_peaks(int arr[][columns]) {
    int curr = 0, peak_counter = 0;

    for (int i = 0; i < rows - 1; i++)
        for (int j = 1; j < columns - 1; j++) {
            curr = arr[i][j];
            for (int k = 0; k <= i + 1; k++) {
                for (int l = j - 1; l <= j + 1; l++) {
                    if (arr[k][l] < curr)
                        peak_counter++;
                    if (arr[k][l] > curr)
                        curr = arr[i][j];
                }
            }

            if (peak_counter == 8)
                printf("peak at (%ld,%ld)\n", i, j);
            
            peak_counter = 0;
        }
}

非常感谢您的帮助。

这是我解决问题的方法。

#include <stdio.h>

#define columns 7
#define rows 6

int arr[rows][columns] = {
   { 5039,  5127,  5238,  5259,  5248,  5310,  5299 },
   { 5150,  5392,  5410,  5401,  5320,  5820,  5321 },
   { 5290,  5560,  5490,  5421,  5530,  5831,  5210 },
   { 5110,  5429,  5430,  5411,  5459,  5630,  5319 },
   { 4920,  5129,  4921,  5821,  4722,  4921,  5129 },
   { 5023,  5129,  4822,  4872,  4794,  4862,  4245 },
};

void find_peaks(int arr[][columns]);

int main() {
    
    find_peaks(arr);

    return 0;
}

void find_peaks(int arr[][columns]) {
    int curr = 0;

    for (int i = 1; i < rows - 1; i++)
        for (int j = 1; j < columns - 1; j++) {
            curr = arr[i][j];
            //left, right, down, up, upper_left, upper_right, lower_left, lower_right
            if (arr[i][j-1] < curr && arr[i][j+1] < curr && arr[i-1][j] < curr && arr[i+1][j] < curr && arr[i-1][j-1] < curr && arr[i-1][j+1] < curr && arr[i+1][j-1] < curr && arr[i+1][j+1] < curr) {

                printf("peak at (%d,%d)\n", i, j);
            }
        }
}

您查找局部最大值的代码存在一些问题:

  • 外循环应该从 i = 1
  • 开始
  • 第三个循环应该从 k = i - 1
  • 开始
  • 在内部循环中更新 curr 似乎没有必要。一旦测试失败并且 k != il != j,您可以立即中断内部循环,但这些额外的测试可能会损害性能而不是提高性能。按照编码,内部循环应该编译成高效的无分支代码。
  • 对于 printf("peak at (%ld,%ld)\n", i, j);
  • 中的 int 个参数,您应该使用 %d
  • columnsrows.
  • 使用大写是惯用的

这是修改后的版本:

#include <stdio.h>

#define COLUMNS 7
#define ROWS 6

int array[ROWS][COLUMNS] = {
    { 5039,  5127,  5238,  5259,  5248,  5310,  5299 },
    { 5150,  5392,  5410,  5401,  5320,  5820,  5321 },
    { 5290,  5560,  5490,  5421,  5530,  5831,  5210 },
    { 5110,  5429,  5430,  5411,  5459,  5630,  5319 },
    { 4920,  5129,  4921,  5821,  4722,  4921,  5129 },
    { 5023,  5129,  4822,  4872,  4794,  4862,  4245 },
};

void find_peaks(int arr[][COLUMNS]) {
    for (int i = 1; i < ROWS - 1; i++) {
        for (int j = 1; j < COLUMNS - 1; j++) {
            int peak_counter = 0;
            int curr = arr[i][j];
            for (int k = i - 1; k <= i + 1; k++) {
                for (int l = j - 1; l <= j + 1; l++) {
                    if (arr[k][l] < curr)
                        peak_counter++;
                }
            }
            if (peak_counter == 8)
                printf("peak at (%d,%d): %d\n", i, j, curr);
        }
    }
}

int main() {
    find_peaks(array);
    return 0;
}

输出:

peak at (2,1): 5560
peak at (2,5): 5831
peak at (4,3): 5821

我不知道你的算法是如何工作的,所以我自己写了一个。

#include <stdio.h>

#define COLUMNS 7
#define ROWS 6

int arr[ROWS][COLUMNS] = {
   { 5039,  5127,  5238,  5259,  5248,  5310,  5299 },
   { 5150,  5392,  5410,  5401,  5320,  5820,  5321 },
   { 5290,  5560,  5490,  5421,  5530,  5831,  5210 },
   { 5110,  5429,  5430,  5411,  5459,  5630,  5319 },
   { 4920,  5129,  4921,  5821,  4722,  4921,  5129 },
   { 5023,  5129,  4822,  4872,  4794,  4862,  4245 },
};

void find_peaks() {

  int get (int x, int y) {
    if (x < 0 || x >= ROWS) return -1;
    if (y < 0 || y >= COLUMNS) return -1;
    return arr[y][x];
  };

  for (int y = 0; y < ROWS; y++) {
    for (int x = 0; x < COLUMNS; x++) {
      int t = arr[y][x];
      if (t <= get(x + 1, y)) continue;
      if (t <= get(x - 1, y)) continue;
      if (t <= get(x, y + 1)) continue;
      if (t <= get(x, y - 1)) continue;
      if (t <= get(x + 1, y + 1)) continue;
      if (t <= get(x - 1, y + 1)) continue;
      if (t <= get(x + 1, y - 1)) continue;
      if (t <= get(x - 1, y - 1)) continue;
      printf("Peak of %d at (%d, %d)\n", t, x, y);
    };
  };
};

int main() {
  find_peaks();
  return 0;
};

如果您实际上并不关心在数组边缘找到峰值,那么您不需要 get() 包装器来检查您是否没有超出数组边界,但是您可以只需让循环从 1 转到 limit-1 即可。如果您不关心对角线,您也可以删除第二组四个 if () continue 语句,但鉴于您指出的正确答案,看来您确实关心。