我只需要一点帮助。我正在做一个我需要 Efficient Way 的任务 要排序一个二维整数数组,其行和列元素已按升序排序。(优先语言C / C ++)。
输入:
1 5 10 15 20
2 7 12 17 22
4 9 18 25 28
11 14 21 26 31
输出:
1 2 4 5 7
9 10 11 12 14
15 17 18 20 21
22 25 26 28 31
提前致谢。
答案 0 :(得分:6)
使用类似于合并排序中使用的合并方法合并列(或行)。
这将利用每个列自行排序的事实。
这应该足够快。
修改强>
似乎标准库中已经存在合并功能。 http://en.cppreference.com/w/cpp/algorithm/merge
答案 1 :(得分:3)
我会使用类似“泛洪填充”的某种算法或像A *这样的路径查找算法。从左上角开始(值1),输出它并向右和向下“展开” - 所以将它们的值(2和5)添加到列表中。这两个都将大于1.现在输出列表中的最小值(值2)并“扩展”它。您将在列表中添加4和7,输出4并“展开”它,依此类推。
请注意,通过保持列表排序,您可以立即输出最小的元素,甚至可以一次输出连续值的多个“运行”(f.e.10,11,12)。所以伪代码将是:
// array a[y][x]
// list L - ordered insertion, additionally stores matrix indices of values
add a[0][0] to L
loop until L is empty
output first element of L
remove first element of L and add its right and bottom neighbors (if any) to L
loop end
编辑:这是一个有效的C实现。
#include <stdio.h>
#include <stdlib.h>
#define COLS 5
#define ROWS 4
int matrix[ROWS][COLS] = {
1, 5, 10, 15, 20,
2, 7, 12, 17, 22,
4, 9, 18, 25, 28,
11, 14, 21, 26, 31
};
struct entry {
int value;
int x, y;
};
entry list[ROWS+COLS]; // Not sure how big the list can get, but this should be enough
int list_len = 0;
void set_list_entry(int index, int value, int x, int y) {
list[index].value = value;
list[index].x = x;
list[index].y = y;
}
void add_to_list(int x, int y) {
int val = matrix[y][x];
int i, pos = list_len;
for (i = 0; i < list_len; i++) {
if (list[i].value == val) return; // Don't add value that is on the list already
if (list[i].value > val) {
pos = i;
break;
}
}
// Shift the elements after pos
for (i = list_len + 1; i > pos; i--) {
set_list_entry(i, list[i - 1].value, list[i - 1].x, list[i - 1].y);
}
// Insert new entry
set_list_entry(pos, val, x, y);
list_len++;
}
int main() {
int iteration = 0;
add_to_list(0,0);
do {
// output first element of list
printf("%i ", list[0].value);
iteration++;
if ((iteration % COLS) == 0) printf("\n");
// add neighbors of first element of list to the list
if (list[0].x < (COLS - 1)) add_to_list(list[0].x + 1, list[0].y);
if (list[0].y < (ROWS - 1)) add_to_list(list[0].x, list[0].y + 1);
// remove first element of list
for (int i = 0; i < list_len; i++) {
set_list_entry(i, list[i + 1].value, list[i + 1].x, list[i + 1].y);
}
list_len--;
} while (list_len > 0);
return 0;
}
请注意有关列表长度的注释。我不确定列表有多大,但我认为COLS+ROWS
应该足够看这个最坏的情况:
1 3 5 7 9 ..
2 y y y y
4 y x x x
6 y x x x
8 y x x x
.
.
如果所有“border”元素都小于最小y
值,那么您将获得一个完整的y
值列表,其中(ROWS - 1) + (COLS - 1)
个元素长。
考虑到这种最糟糕的情况,我想这不是最有效的解决方案,但我认为这是一个优雅而简洁的解决方案。
答案 2 :(得分:0)
为什么我们不把这个问题视为“合并N个排序列表,每个都有k个元素”。
创建一个k元素的最小堆。将排序列表中的每个最小元素放在该最小堆中。弹出堆的根。现在插入其元素为根的列表的下一个元素。
通过这种方式,我们得到N * k log(k)的复杂性。
在上面的例子中它将是N ^ 2log(N),其中N是一行中元素的数量。
答案 3 :(得分:-1)
这是一个提示 - 假设这是一个普通的2D C数组,使用一些类型转换,你应该能够将它解释为一维数组。