【问题标题】:Need higher performance for three-way quick sort三向快速排序需要更高的性能
【发布时间】:2016-07-19 18:39:54
【问题描述】:

我目前正在尝试实现三分区快速排序。下面的代码工作正常,但运行时间不够。总的来说,我对数据结构、算法和“深度”编程是新手,所以我试图摆弄它以使其在更短的时间内工作的尝试基本上没有结果。 (内存性能很好。)

我的直觉是改变枢轴,但我担心它不会是三向快速排序,那么。

#include <iostream>
#include <vector>
#include <cstdlib>

using std::vector;
using std::swap;


int partition3(vector<int> &a, int l, int r) {

    int x = a[l]; 
    int j = l;
    int k = r;
    int i = l+1; 

    while (i <= k) {
        if (a[i] < x) {
          swap(a[i],a[j]);
          j++; 
          i++;
        }
        else if(a[i] > x) {
            swap(a[i],a[k]);
            k--;
        }
        else {
            i++;
        }
    }

    return j;
}

void randomized_quick_sort(vector<int> &a, int l, int r) {

    if (l >= r) {
        return;
    }

    int k = l + rand() % (r - l + 1);
    swap(a[l], a[k]);

    while (l < r) {
        int m = partition3(a, l, r);
        if ((m-l) < (r-m)) {
            randomized_quick_sort(a, l, m - 1);
            l = m + 1; 
        }
        else {
            randomized_quick_sort(a, m + 1, r);
            r = m - 1;
        }
    }
}

int main() {
    int n; 
    std::cin >> n;
    vector<int> a(n);
    for (size_t i = 0; i < a.size(); ++i) {
        std::cin >> a[i];
    }
    randomized_quick_sort(a, 0, a.size() - 1);
    for (size_t i = 0; i < a.size(); ++i) {
        std::cout << a[i] << ' ';
    }
}

【问题讨论】:

  • rand() 可能需要一些时间。需要随机吗?你能找到更快的随机数生成器吗?
  • 您能更明确地说明您测量的内容吗? IO 会很慢而且很吵。 rand() 依赖于实现。确保在测量速度时不包括它们。
  • 这是给评分系统的——我提交这个是为了在线测试。
  • 添加快速自定义随机函数source
  • 我投票结束这个问题,因为这基本上是一个代码审查(你不能在堆栈交换网络中选择另一个站点)。

标签: c++ algorithm performance time quicksort


【解决方案1】:

在现实世界中,排序是一个相当复杂的问题。尝试查看一些有效的实现,例如 C++ 标准库的实现提供的那些。浏览网页、阅读文章、查看讨论......

只是一些注释:

  1. 随机数生成(相对)昂贵,它会显着减慢快速排序。 (但是,它也可以对某些类型的数据做相反的事情。)
  2. 整数除法(相对)非常昂贵,可能比随机数生成更昂贵。
  3. 在实践中很少单独使用纯快速排序。通常,它与插入排序结合使用,因为递归调用对于非常小的分区效率低下(阈值通常设置在 8 到 16 个元素之间)。
  4. 为了防止快速排序最坏情况的复杂性,通常会检查递归级别,如果它超过某个阈值 (2 x log_2(n)),则使用另一种算法(通常是堆排序)对其余数据进行排序。

等等……

更新

还有两个想法:

  1. 在多核/多核环境中,并行算法可能会为您提供最佳加速。但是设计一个并行快速排序绝非易事。大部分复杂性在于有效的并行分区和负载平衡。 Libstdc++ 并行模式有一个很好的 OpenMP 实现。或者,您也可以查看我的 AQsort:https://github.com/DanielLangr/AQsort
  2. 为了提高快速排序的效率,请使用尾调用消除/优化。它大大减少了所需的调用堆栈空间。

【讨论】:

  • 随机枢轴在实践中可以防止最坏情况的复杂性,因此除非您已经更改了 (1),否则不要执行 (4)。假设随机数合理,时间比 n log n 的某个恒定倍数更差的概率是微乎其微的(即,不会比 GUID 碰撞或宇宙射线干扰您的机器之类的事情更可能)。而且随机枢轴比 introsort 更容易编码......
  • 是的。我昨天做了很多关于排序的在线研究。嗯......我想我会先尝试#3:对低于特定长度阈值的测试用例使用不同的排序。
  • 然后,请注意,您只能在算法的最后运行插入排序一次。参见,例如,Libstdc++-v3 source code
  • 当你的东西正常工作时,你可以将性能与 std::sort 进行比较。 std::sort (C++) 通常比经典的 C qsort 快,例如因为比较操作是在编译时绑定的,而不是使用 fcn ptrs。
  • @ErikAlapää 并不是这段代码本身不起作用,而是它打破了时间限制。但是在类似的事情上看到旧 C 和 C++ 之间的区别是非常有趣的。
【解决方案2】:

我在这里看到了非常可靠的代码。

如果您想保留算法,加速它的最佳方法是将其从递归更改为迭代。这不会是一个巨大的提升,但它会有所帮助,每个函数调用都是一个可以避免的开销。手动交换也是不错的选择。

您还可以获得一些速度以避免额外的内存分配,因此您应该尝试尽可能多地重用您的变量,例如,在 while 中声明 int m。

【讨论】:

  • 谢谢。这是一个涵盖分而治之范式的作业,所以我假设(我认为)在进行递归时应该有一种方法可以通过。不过,我会记住这一点:我开始变得非常沮丧。我今天还有其他事情要做。
猜你喜欢
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 2021-10-01
  • 2012-08-12
  • 2018-09-29
  • 1970-01-01
相关资源
最近更新 更多