【问题标题】:quicksort, can it be made to output the first m sorted values in an N dimension array, thereby being faster than a full N sort快速排序,是否可以输出 N 维数组中的前 m 个排序值,从而比完整的 N 排序更快
【发布时间】:2013-11-14 16:30:39
【问题描述】:

快速排序是一种众所周知的算法,但破译 C 很复杂(对我而言)。内联版本大大加快了速度http://www.corpit.ru/mjt/qsort.html‎。

但是,它是否可以轻松转换为输出 N 元素数组的前 m 个样本?

所以在第一个 m 个样本排序后简单地停止排序的调用?我怀疑不是因为它对块进行快速排序,然后将块缝合在一起以形成最终输出。如果我将初始快速排序块的大小设置为 m 的大小,那么我处于一个糟糕的位置,没有利用 qsort 中的聪明东西。

提前致谢

格格

【问题讨论】:

  • qsort 是一个 C 库函数。快速排序是一种排序算法。我假设您实际上是在询问快速排序算法? qsort 函数本身可能使用也可能不使用快速排序算法。
  • 原则上是的。这个想法被称为部分排序。 (有关 C++ 中相关库函数的讨论,请参阅 here)。对于 C,我认为您必须找到/编写自己的实现。
  • 另一种可能是priority queue。它就像一个堆栈,但每次你弹出它时,它都会给你堆栈中的最大值。您可以调用它 n 次以获得最大的 n 个值。它应该相当快,如果 n 肯定比完整的快速排序快
  • @Aaron McDaid 当 OP 的 n 明显小于 N 时,您的优先队列想法是一个非常好的解决方案。我会投票赞成。
  • 您是在询问Quickselect 算法吗?

标签: c algorithm quicksort


【解决方案1】:

按照@R.. 的建议,使用Quickselect 获取第一个k 元素,然后对它们进行排序。获取元素的运行时间为 O(N),排序为 O(k log k)。

但是,emperical evidence suggests 认为,如果要选择的项目数 (k) 小于元素总数 (N) 的 1%,那么使用二叉堆将比快速选择后排序更快。当我必须从 200 万个列表中选择 200 个项目时,堆选择算法要快得多。有关详细信息,请参阅链接的博客。

【讨论】:

    【解决方案2】:

    (重述问题:给定 N 个项目,找出其中最大的 m 个。)

    一个简单的解决方案是priority queue。将所有 N 个项目送入队列,然后从列表中弹出顶部 m 个项目。喂入 N 个项目将是 O(N log m)。每个单独的 pop 操作是 O(log m),因此删除顶部 n 项将是 O(m log m)。


    就地算法应该相对简单。我们是 N 个元素的数组。数组中的每个位置都有编号,编号介于 1 和 N(含)之间。对于数组中的每个位置,取其位置并除以 2(必要时向下舍入),并将该位置定义为其 父位置。除了位置 1 之外,每个位置都将有一个父位置。大多数职位(不是全部)都会有两个孩子。例如:

    node position:  1 2 3 4 5 6 7 8 9 ...
    parent:         - 1 1 2 2 3 3 4 4 ...
    

    我们希望交换节点,直到每个节点的值小于(或等于)其父节点。这将保证最大值位于位置 1。将数组重新排序以具有这种形式非常容易。只需从位置 1 到 N 依次遍历节点,并在其上调用该函数一次:

    void fixup_position(int x) {
       if(x==1)
          return;
       int parent_position = (x/2) ; // rounding-down where necessary
       if (data[x] > data[parent_position]) {
          swap(data[x], data[parent_position]);
          check_position(parent_position);  // note this recursive call
       }
    }
    
    
    for(x = 1; x <= N; ++x) {
        fixup_position(x);
    }
    

    (是的,我正在计算位置为 1 的数组,而不是 0!实际实现时必须考虑到这一点。但这更容易理解优先级队列的逻辑。)

    递归调用的平均次数(因此swaps)是一个常数(如果我没记错的话,是2)。所以这会很快,即使是大型数据集。

    值得花一点时间来理解为什么这是正确的。就在调用fixup_position(x) 之前,直到(但不包括x)的每个位置都处于“正确”状态。 “正确”是指它们没有完全排序,但每个节点都小于其父节点。引入了一个新值(在位置 x),并将在队列中“冒泡”。您可能会担心这会使其他职位及其父子关系无效,但不会。一次只有一个节点处于无效状态,并且会一直冒泡到它应有的位置。

    这是将您的数组重新排列到优先级队列中的 O(N) 步骤。

    删除顶部 n 项。经过上面的方法,很明显最大的数字会在位置1,但是第二大,第三大,等等呢?我们所做的是从位置 1 一次弹出一个值,然后重新排列数据,以便将下一个最大值移到位置 1。这比 fixup_position 稍微复杂一些。

    for(int y = 1; y <= m; ++y) {
       print the number in position 1 .... it's the next biggest number
       data[1]  =  -10000000000000; // a number smaller than all your data
       fixup_the_other_way(1);  // yes, this is '1', not 'y' !
    }
    

    fixup_the_other_way 在哪里:

    void fixup_the_other_way(int x) {
        int child1 = 2*x;
        int child2 = 2*x+1;
        if(child1 > N)  // doesn't have any children, we're done here
            return;
        if(child2 > N) { // has one child, at position[child1]
           swap(data[x], data[child1]);
           fixup_the_other_way(child1);
           return;
        }
        // otherwise, two children, we must identify the biggest child
        int position_of_largest_child = (data[child1]>data[child2]) ? child1 : child2;
        swap(data[x], data[position_of_largest_child]);
        fixup_the_other_way(position_of_largest_child);
        return;
    }
    

    这意味着我们打印出最大的剩余项目,然后用一个非常小的数字替换它,并强制它“冒泡”到我们数据结构的底部。

    【讨论】:

    • 如果有人看到错误,请继续自己进行任何编辑,我真的应该继续我的日常工作;-)
    • 概念修改:如果 only n 最小的项目曾经从队列中弹出,队列大小可能被限制为 power(2,n)。由于尝试添加超过 power(2,n) 个元素,因此新候选元素需要小于最后一个元素,否则将没有意义将其添加到优先级队列中。所以它或最后一个元素被扔掉了。如果 N = 1,000,000 且 n = 10,则优先级队列的最大大小为 1023,最大深度为 10。添加 1023 个元素后,最后一个 (N-1023) 需要进行 10 次最坏情况比较。怀疑这个算法是 O(Nn) 当 n log2(N)) 当 n 接近 N.
    • 先生们,非常感谢以上所有的好东西。我一定会试一试的。
    【解决方案3】:

    有两种方法可以有效解决问题:-

    1.> 优先队列

    算法:-

    1. 将前 n 项插入优先级队列,最大堆

    2. 查看最大元素以检查当前比较的元素是否小于该元素

    3. if less 删除顶部元素并添加当前元素

    4. 对所有 N-n 个元素执行步骤。

    2.> 您的问题可以简化为选择问题:-

    算法

    1. 在 N 个元素上随机选择第 n 个元素(平均情况为 O(N))

    2. 使用 qsort 或任何其他有效的排序算法对前 n 个元素进行排序

    使用这两种算法,您将获得平均情况 O(N) 性能

    【讨论】:

      猜你喜欢
      • 2016-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-14
      • 2018-02-08
      • 2015-07-21
      相关资源
      最近更新 更多