对一行二进制数组进行排序。列元素已排序

时间:2012-01-12 01:27:33

标签: c++ c

我只需要一点帮助。我正在做一个我需要 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

提前致谢。

4 个答案:

答案 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数组,使用一些类型转换,你应该能够将它解释为一维数组。