将具有排序行的2D数组合并为一个大的1D数组

Merging a 2D array with sorted rows into a big 1D array

本文关键字:数组 1D 一个 合并 排序 2D      更新时间:2023-10-16

给定一个2d数组,每一行从左到右,从最小到最大排序,我想把整个数组按从小到大排序成一个1D数组。

的行数为N,列数为M。需要的复杂度是MNlog(N)

我想做的是,在二维数组上做一些归并排序,每次发送2行给函数,这就是我卡住的地方。

函数的签名是

void sort_rect(int a[N][M], int b[])

我保证b的1d数组有足够的空间容纳2d数组的所有元素。#C!!

使用标准方法(合并排序数组然后排序)将得到O(NMLog(NM))。如果你想要一个有效的方法,那么你应该使用最小堆数据结构。你可能想了解堆数据结构。

  1. 创建一个大小为N*M的输出数组,这将保存输出的排序数组

  2. 创建一个大小为N的最小堆,插入每个排序数组的第一个元素

  3. 从堆中移除顶部元素(最小)并将其放入输出数组中。将这个被删除的元素替换为该被删除元素所在的同一数组中的下一个元素。重复此操作,直到所有元素都被考虑在内。

复杂性将是O(NMLog(N))

由于a[M][N]中的所有元素都位于顺序内存中,因此可以将该内存视为平面内存。你可以这样排序:

int *c = (int *)a;

和排序c,给定数组的大小为M*N

或者你可以复制到b,通过定义b:

int b[sizeof(a) / sizeof(int)];
memcpy(b, a, sizeof(a));

和现在排序b

考虑一个归并排序,但是应用于N个数组而不是2个。对于每一行,都可以保留当前考虑的元素的索引。现在我们需要一些东西来比较所有N个值(而不仅仅是2个)。你可以做的是使用一个堆(priority_queue),它的元素结构像这样:

struct Element {
   int Value;
   int Row; //tells you which row in the 2d array the value comes from
}

算法如下:

  1. 将从第0列开始的所有值添加到优先级队列
  2. 声明一个数组,它将为每一行保留当前考虑的索引。初始化为0
  3. 在循环中(直到元素用完)
    • 检查队列顶部的元素(element = queue.top())
    • 添加element.Value到1d数组
    • 当前考虑的element.Row索引增量
    • 从优先队列的顶端移除元素(queue.pop())

得到的1d数组被排序,复杂度为0 (MNlog(N))。这是因为您考虑了M*N个元素,并且对于每个元素添加/从priority_queue中删除它需要log(N)时间,因为在任何给定时刻堆保留的元素不超过N个。

我认为将2d数组视为1d并排序会导致MNlog(MN)复杂性,这有点糟糕。