【问题标题】:Most efficient way to sort a 2d array with sorted rows into 1d sorted array将具有排序行的二维数组排序为一维排序数组的最有效方法
【发布时间】:2014-04-23 10:37:49
【问题描述】:

给定一个具有 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)

如果我的复杂度计算有误,请告诉我。

还有比这更有效的方法吗?

【问题讨论】:

    标签: algorithm sorting


    【解决方案1】:

    您基本上有n 排序列表,每个大小为k。你需要泛化merge-sort,也就是k-way merge。

    这个想法是保留一个min-heap,它包含每个列表中的最小元素。

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

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

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

    请注意,这通常称为external sort(或者确切地说是外部排序第二部分的近似变体)。

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

    【讨论】:

      【解决方案2】:

      这可以使用排序合并来完成,这将花费 o(rows*cols) 时间,即元素总数和 o(rows) 空间复杂度。

      这个问题的java代码如下:(考虑rows = 3 and 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++;
          }
      

      【讨论】:

        最近更新 更多