【问题标题】:Sort an array which is first increasing then decreasing对先增后减的数组进行排序
【发布时间】:2013-01-23 13:34:55
【问题描述】:

给定一个数组,该数组的元素按升序排列,直到最大值,然后按降序排列。

Eg. int a[] = { 10, 12, 14, 16, 15, 13, 11}.

这个数组如何高效排序?

数组需要就地排序。

【问题讨论】:

  • 数组需要就地排序。
  • 将此添加到问题中 - 您应该可以对其进行编辑

标签: arrays algorithm sorting


【解决方案1】:

找到最大值,然后将数组反转到该值。然后对两个子数组应用合并 - 第一个包含最大值,然后是其余数组。这将具有线性计算复杂度,并且需要线性附加内存。

在你的情况下:

a[] = { 10, 12, 14, 16, 15, 13, 11} => {10,12,14,16}, {15,13,11}

=> 反向(线性,就地)=>

{16,14,12,10}, {15,13,11}

=> 合并(线性,附加线性内存)=>

{16,15,14,13,12,11,10}

编辑:关于如何在没有额外内存的情况下合并两个数组,请查看this answer

【讨论】:

  • 我给出了类似的方法来进行排序。但我被要求做到位。你能告诉我我们如何就地对这个数组进行排序。
  • i=4, { 10, 11, 12, 14, 15, 13, 16} 这是对的吗?为什么交换 14 而不是 13?
  • @Толя 我只考虑最后一个数字。我并不是说我执行了最少数量的操作,只是说这应该可以工作。
  • @Толя 试着自己弄清楚。证明其正确性的最简单方法是证明始终成立的事物。在这种情况下,证明在每一步中,直到 i 的数组都被排序,并且数组 [i, size-1] 仍然根据语句排序。
  • @Ivaylo:很好的解决方案。但是对于 i=4 它确实失败了。我认为我们可以通过进行以下更改来处理这个问题:如果 i 越过枢轴元素所在的索引,那么我们必须首先减少右索引,然后将索引处的元素与其进行比较,然后按照该过程直到达到正确的索引。跨度>
【解决方案2】:

我的解决方案:

  1. 获取 2 个指针数组开始数组结束

  2. 从两个指针中写入一个最小值(如果需要降序排序,则为最大值)到结果数组中,然后移位 指向 1 位置的指针(开始指针 +1 位置和结束指针 -1 位置

  3. 重复直到开始指针位于结束指针之后。

解的复杂度为 O(N)。 所需内存为 O(N)

伪代码:

function Sort(a)
{
  startPointer = 0;
  endPointer = a.length-1;
  result = new Array of size a.length
  while (startPointer <= endPointer)
  {
    var newValue;
    if (a[startPointer] < a[endPointer])
    {
      newValue = a[startPointer];
      startPointer +1
    }
    else
    {
      newValue = a[endPointer];
      endPointer -1
    }
    result[a.length - startPointer - endPointer] = newValue;
  }

  return result;
}

更新问题的解决方案:

作为解决方案使用数组第一部分的部分排序。

指针(10 和 11) {10、12、14、16、15、13、11}

指针(12 和 11) 交换 12 和 11 {10、11、14、16、15、13、12}

指针(14 和 12) 交换 14 和 12 {10, 11, 12, 16, 15, 13, 14} // 将指针从 14 移动到 13 一个较小的位置。

现在我们已经对 {10, 11, 12} 和 {16, 15, 13, 14} 的子问题进行了排序(子问题的 N 减少了两倍)

这个算法的复杂度是:O(N) + (N/2) + O(N/4) + ... 总共是 O(N)

图片以获得更好的说明:

【讨论】:

  • 你测试过这个算法看它是否有效吗?我认为这不是正确的解决方案。我相信您需要将数组划分为已排序的子数组并合并这些子数组以获取已排序的数组。如果使用合并排序来合并“K”个排序的子数组,这可以通过 O(nLog(k)) 复杂度来完成。
【解决方案3】:

使用问题的属性。

您不需要对已经排序的数组进行排序。找到slope变化的点,然后使用合适的algorithm得到一个完整的排序数组。

您可以考虑实现一个bitonic sorter,它可以有效地使用此属性。

【讨论】:

  • @Толя 我建议了一个算法。你能撤消我的反对票吗?