将排序行的2d数组排序为1d排序数组的最有效方法

时间:2014-04-23 10:37:49

标签: algorithm sorting

给定一个带有n行和k列的二维数组(一个矩阵),它的行是排序的,列是未指定的,那么最有效的排序算法是什么?

例如:

Input (n = 3 ; k = 4):
1 5 8 10
3 4 5 6
2 3 3 9

Output:
1 2 3 3 3 4 5 5 6 8 9 10

这是纯粹的算法问题,因此某些语言的特定.sort()方法对我没有帮助,因为我实际上在运行时复杂性方面存在差异。

我的想法是如下算法:

- Build a Binary Search tree with n nodes. Each node contains:
  ID - of the row it refers to;
  Value - The number at the "head" of the row.
- Sort the tree where the sorting key are the values.
- Find the lowest valued node.
- Do while the tree has a root:
  - Take the lowest value and append it to the new array.
  - Update the node's value to the next one in the same row.
  - If the updated value is null, delete that node.
    - else re-sort the tree.
  - If the node moved, the first node it swapped with will be the next lowest
    - else, if it didn't move, it's the new lowest.

如果我没弄错,运行时复杂度为O(n*k * log n),因为我正在对树进行排序n*k次,这需要O(log n)次,并且找到下一个最低的过程是O(1)

如果我的复杂性计算错误,请告诉我。

有没有比这更有效的方法?

2 个答案:

答案 0 :(得分:3)

您基本上拥有n个排序列表,每个列表的大小为k。您需要merge-sort的泛化,这是k-way合并。

我们的想法是保留min-heap,其中包含每个列表中最小的元素。

现在,迭代地弹出堆的最小值。请将此数字设为x,并说它来自行i。现在,将x附加到结果列表,并将最小的行添加到行i中的下一个元素(如果存在这样的元素)

重复直到所有元素都用尽。

复杂性为O(n*k*logn),考虑到您正在排序n*k元素并且需要遍历所有元素,这非常有效。使用二进制堆的常量非常好。

请注意,这通常被称为external sort(或者与外部排序的第二部分完全相同)。

这与您建议的算法非常相似,但由于使用堆而不是效率较低的树,可能会运行得更快(具有更好的常量)。
另请注意,如果您使用常规的'二叉树,你得到O(n^2k)的复杂性,因为不能保证树的高度。您需要self balancing binary search tree才能获得O(nklogn)运行时间。

答案 1 :(得分:0)

这可以使用Sorted Merge来完成,它将占用o(rows * cols)时间,即元素总数和o(行)空间复杂度。

此问题的java代码如下:(考虑rows = 3和cols = 4)

    for(int i=0;i<3;i++)
    {
        index[i] =0;
    }

    int count=0;
    int a;
    int b;
    int c; 

    while(count<(ROWS*COLS))
    {
        int smallest;
        if(index[0]>=COLS)
            a= Integer.MAX_VALUE;
        else
            a= matrix[0][index[0]];
        if(index[1]>=COLS)
            b = Integer.MAX_VALUE;
        else
            b = matrix[1][index[1]];
        if(index[2]>=COLS)
            c = Integer.MAX_VALUE;
        else
            c = matrix[2][index[2]];
        if(a<=b && a<=c){
            // a is smallest
            smallest = a;
            index[0] = index[0] +1;

        }else if(b<=c && b<=a){
            //b is smallest
            smallest = b;
            index[1] = index[1] + 1;
        }else{
            //c is smallest
            smallest = c;
            index[2] = index[2] + 1;
        }
        System.out.print(smallest + ", ");
        count++;
    }