对增加的数组进行排序

时间:2013-12-11 01:16:48

标签: c algorithm sorting

伪码:

S = {};
Loop 10000 times:
    u = unsorted_fixed_size_array_producer();
    S = sort(S + u);

我需要一个有效的sort实现,它接受一个排序数组和一个未排序数组,然后对它们进行排序。但是我们知道经过几次迭代后, size(S)将比 size(u)大得多,这是先验的。

更新:还有另一个先验: u 的大小已知,例如10或20,循环时间也是已知的。

更新:我实施了@Dukelnig在C https://gist.github.com/blackball/bd7e5619a1e83bd985a3中建议的算法,该算法符合我的需要。谢谢!

4 个答案:

答案 0 :(得分:3)

排序u,然后合并Su

合并只需要同时迭代两个已排序的数组,并选择较小的元素并在每一步递增该迭代器。

运行时间为O(|u| log |u| + |S|)

这与merge sort非常相似,因此可以从那里得到排序数组。

一些用于合并的Java代码,派生自Wikipedia :( C代码看起来不会那么不同)

static void merge(int S[], int u[], int newS[])
{
   int iS = 0, iu = 0;

   for (int j = 0; j < S.length + u.length; j++)
      if (iS < S.length && (iu >= u.length || S[iS] <= u[iu]))
         newS[j] = S[iS++];  // Increment iS after using it as an index
      else
         newS[j] = u[iu++];  // Increment iu after using it as an index
}

这也可以通过从后面进行就地(在S中,假设它有足够的额外空间) 这是一些有效的Java代码:

static void mergeInPlace(int S[], int SLength, int u[])
{
   int iS = SLength-1, iu = u.length-1;

   for (int j = SLength + u.length - 1; j >= 0; j--)
      if (iS >= 0 && (iu < 0 || S[iS] >= u[iu]))
         S[j] = S[iS--];
      else
         S[j] = u[iu--];
}

public static void main(String[] args)
{
   int[] S = {1,5,9,13,22, 0,0,0,0}; // 4 additional spots reserved here
   int[] u = {0,10,11,15};
   mergeInPlace(S, 5, u);
   // prints [0, 1, 5, 9, 10, 11, 13, 15, 22]
   System.out.println(Arrays.toString(S));
}

为了减少比较次数,我们也可以使用二进制搜索(尽管时间复杂度保持不变 - 这在比较昂贵时非常有用)。

// returns the first element in S before SLength greater than value,
//   or returns SLength if no such element exists
static int binarySearch(int S[], int SLength, int value) { ... }

static void mergeInPlaceBinarySearch(int S[], int SLength, int u[])
{
   int iS = SLength-1;
   int iNew = SLength + u.length - 1;

   for (int iu = u.length-1; iu >= 0; iu--)
   {
      if (iS >= 0)
      {
         int index = binarySearch(S, iS+1, u[iu]);
         for ( ; iS >= index; iS--)
            S[iNew--] = S[iS];
      }
      S[iNew--] = u[iu];
   }
   // assert (iS != iNew)
   for ( ; iS >= 0; iS--)
      S[iNew--] = S[iS];
}

如果S不必是数组

以上假设S必须是一个数组。如果不是,binary search tree之类的内容可能会更好,具体取决于uS的大小。

运行时间为O(|u| log |S|) - 只需替换一些值即可查看哪个更好。

答案 1 :(得分:0)

如果您确实必须始终为S使用文字数组,那么最好的方法是将新元素单独插入已经排序的{{1} }。即基本上对每个新批次中的每个元素使用经典插入排序技术。从某种意义上说,插入阵列是昂贵的(你必须移动元素),这将是昂贵的,但这是必须使用S数组的代价。

答案 2 :(得分:0)

因此,如果S的大小远远大于u的大小,那么对于大多数排序的数组而言,这不是您想要的有效排序吗?传统上这将是插入排序。但是你只会通过实验和测量来了解真正的答案 - 尝试不同的算法并选择最好的算法。如果没有实际运行代码(也许更重要的是,使用您的数据),您就无法可靠地预测性能,即使使用与排序算法一样好的东西也是如此。

答案 3 :(得分:0)

假设我们有一个大型n的大型排序列表和一个大小为k的小型排序列表。

二进制搜索,从结尾开始(位置n-1n-2n-4和&amp; c),作为较小列表中最大元素的插入点。将较大列表k元素的尾端向右移动,插入较小列表的最大元素,然后重复。

因此,如果我们有列表[1,2,4,5,6,8,9][3,7],我们会这样做:

[1,2,4,5,6, , ,8,9]
[1,2,4,5,6, ,7,8,9]
[1,2, ,4,5,6,7,8,9]
[1,2,3,4,5,6,7,8,9]

但我会建议你在使用有趣的合并程序之前,先对列表进行连接并对整个事情进行排序。