【问题标题】:Why is my quicksort implementation slow when given a presorted input?为什么在给定预排序输入时我的快速排序实现很慢?
【发布时间】:2018-12-21 03:04:53
【问题描述】:

我正在尝试实现快速排序,以便可以在不同的输入上分析它的运行时间。我下面的实现在预排序的输入(升序的整数)上运行得非常糟糕。

给定整数 1-5000,这里是我的排序的运行时:

  • 随机排序输入:0.052 秒
  • 降序输入:0.065 秒
  • 升序输入:0.209 秒

给定整数 1-50000,这是我的排序的运行时:

  • 随机输入:0.585 秒
  • 降序输入:1.598 秒
  • 升序输入:6.540 秒

我不确定是什么导致预排序输入运行时间过长。

int median(vector<int> *input, int left, int right) {
    int mid = (right + left) / 2;
    int temp;

    // This method also orders the selected left, mid, and right values
    if ((*input)[mid] < (*input)[left]) {
        temp = (*input)[mid];
        (*input)[mid] = (*input)[left];
        (*input)[left] = temp;
    }
    if ((*input)[right] < (*input)[left]) {
        temp = (*input)[left];
        (*input)[left] = (*input)[right];
        (*input)[right] = temp;
    }
    if ((*input)[mid] < (*input)[right]) {
        temp = (*input)[mid];
        (*input)[mid] = (*input)[right];
        (*input)[right] = temp;
    }

    temp = (*input)[mid];
    (*input)[mid] = (*input)[right-1];
    (*input)[right-1] = temp;

    return (*input)[right-1];
}

void quickSort2(vector<int> *input, int left, int right) {
    if (left < right) {
        // Get pivot (median of 3)
        int pivot = median(input, left, right);
        int temp;

        int i = left, j = right - 1;
        for (; ; ) {
            while ((*input)[++i] < pivot) {}
            while (j > 0 && (*input)[--j] > pivot) {}
            if (i < j) {
                temp = (*input)[i];
                (*input)[i] = (*input)[j];
                (*input)[j] = temp;
            } else {
                break;
            }
        }

        temp = (*input)[i];
        (*input)[i] = (*input)[right - 1];
        (*input)[right - 1] = temp;

        quickSort(input, left, i - 1);
        quickSort(input, i + 1, right);
    }
}

【问题讨论】:

  • 你试过debugging 看看它到底在做什么吗?您可以专门尝试分析数组的相关部分(在中值调用之前和之后)和每个步骤的枢轴。
  • 为什么i和j是全局变量
  • 因为您使用最右边的元素作为枢轴,并且在排序列表中完成此操作时,这会导致长期错误的枢轴选择。这已详细介绍:geeksforgeeks.org/when-does-the-worst-case-of-quicksort-occur
  • 你为什么将 pointers 传递给向量而不是使用引用?你可以使用std::swap吗?
  • 附带说明,我不会更改中值选择中元素的顺序。这是一个副作用,方法名称肯定没有清楚地表达出来,听起来像是一个纯粹的“get”方法。

标签: c++ algorithm performance sorting quicksort


【解决方案1】:

因为您使用最右边的元素作为枢轴,并且在排序列表中完成此操作时,这会导致长期错误的枢轴选择。这已详细介绍:geeksforgeeks.org/when-does-the-worst-case-of-quicksort-occur

尝试更改您的第三个条件:

if ((*input)[mid] < (*input)[right]) {

if ((*input)[right] < (*input)[mid]) {

否则,交换会将最右边(最大)的元素放入 [mid],然后您(最终)将其作为输出返回。

为清晰起见进行了编辑

【讨论】:

  • 将您的评论信息添加到您的答案中。我们希望答案是完整的。您选择对排序时间有极端影响的枢轴是正确的。使用最右边的枢轴是排序输入的最坏情况。
  • @DavidC.Rankin 谢谢。
  • 这绝对是问题所在,谢谢。我在右/左检查中犯了同样的错误,只是忘记修复中/右检查。为选择中值所做的所有努力,我最终选择了最右边的值作为支点。哎呀。对于 5000 和 50000 个输入,运行时间现在分别降至 0.030、0.028、0.014 秒和 0.374、0.330、0.185 秒。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-19
  • 2021-12-04
  • 2011-06-02
  • 1970-01-01
  • 2015-06-25
  • 2016-02-17
  • 2017-03-18
相关资源
最近更新 更多