当选择最左侧或最右侧的元素作为枢轴时,快速排序显然采用 O(n^2)
Quick sort apparently taking O(n^2) when left or right-most element is selected as pivot
嗯,我正在尝试学习快速排序并为其实现以下代码。但是,当我以最左边或最右边的元素作为枢轴时,它似乎在 O(n^2) 而不是 O(nlogn) 中运行......
我无法弄清楚我的代码出了什么问题,但我很可能犯了一些非常基本的愚蠢错误;任何人都可以帮助我并解释我哪里出错了?
提前非常感谢!这是我的代码:
#include <iostream>
#include <vector>
typedef int64_t int64;
int64 numberOfComparisons;
using namespace std;
int partitionAroundPivot(vector<int64>& a, int l, int r) {
numberOfComparisons = numberOfComparisons + (r - l) - 1 ;
int ppos;
ppos = l;
int64 p = a[ppos]; //Gives pivot
if(ppos != l)
swap(a[ppos], a[l]);
int i = l + 1, j;
for(j = l + 1; j <= r; j++){
if(a[j] < p)
{
swap(a[j], a[i]); //Swap with leftmost element bigger than pivot, i.e. v[i]
i++;
}
}
//Now pivot needs to go to its proper place
swap(a[l], a[i - 1]);
return ppos; //WRONG, will return l always, need to return i-1
}
void quickSort(vector<int64>& a, int l, int r) //Inplace so no return stuff
{
if( r - l <= 0)
return ;
int pivotPosition = partitionAroundPivot(a, l, r);
cout << "Called Qsort with positions l " <<l << " r " << r << " Pivot pos " << pivotPosition << endl;
for (int i = l; i < r; i++)
cout << a[i] <<" " ;
cout << endl;
quickSort(a, l , pivotPosition - 1 );
quickSort(a, pivotPosition + 1 , r );
}
int main() {
vector<int64> x = {3, 2, 1, 8, 6, 7, 6, 4};
quickSort(x, 0, x.size() -1);
return 0;
}
部分输出如下:
Called Qsort with positions l 0 r 9 Pivot pos 0
1 2 3 4 6 10 9 5 7
Pivot: 2
Called Qsort with positions l 1 r 9 Pivot pos 1
2 3 4 6 10 9 5 7
Pivot: 3
编辑:我问这个问题的部分原因是因为我应该从理论上计算总共完成的比较数量,我只是使用(每个分区调用时的子数组大小 - 1)作为值(实际的会有所不同,我知道因为只有部分比较实际发生)。这在上面的 numberOfComparisons 变量中可见一斑。
现在的问题是,对于 100 个数字进行排序,所有数字都是从 1-100 的,没有一个唯一且大部分是随机的,它显示计算次数为 4851,接近 100*99/2 又名 n*(n-1)/2,其中 n = 100。这让我相信它正在做 O(n^2) 时间。这是对的吗...?
编辑2:我毕竟太愚蠢了。分区AroundPivot总是返回l,也就是子数组的第一个位置,导致其中一个拆分是零长度的子数组,另一个是数组的其余部分。我需要传回 a[l] 实际去的位置,而不是 l;在这种情况下为 I-1。我猜是吸取的教训。
非常感谢你们的帮助,伙计们!
log n),但平均而言,在最坏情况下是 O(n^2),在最佳情况下是 O(nlogn)。获得良好效率的最重要方面是选择一个好的枢轴。
在您的程序中,您选择了最差的枢轴之一,因为如果您选择第一个或最后一个,在有序(或逆序)向量的情况下,您的算法效率最差。
这就是为什么您必须考虑选择透视的算法。最常用的方法之一是选择三个元素的中位数,例如,第一个、中间和最后一个元素。因此,应用于有序向量的算法是 O(nlogn)。
更新:复杂性由增长概况决定,而不是特定案例。事实上,对于问题的特定大小,您可以有一个非常高的值,而当问题大小变得非常大时,配置文件会更平滑地增加。在检查任何内容之前,使用几个单独的值运行程序,达到非常大的 n。
- 如何修复我的快速排序实现?
- C++运行时错误与快速排序算法抛出堆栈转储错误
- 在 MIPS 中快速排序
- 不正确的比较和交换计数器输出用于快速排序功能
- 使用 std::vector C++快速排序,EXC_BAD_ACCESS代码 2
- 使用快速排序对 C++ 中的可视化工具错误进行排序
- 快速排序 - 三个中位数枢轴选择 - 某些元素顺序不正确
- 并行快速排序分区中的隔离错误
- 实现 3 路分区以实现快速排序
- 为什么这个快速排序实现给出了一个奇怪的输出
- 我的快速排序在对预排序的项目进行排序时失败,如何改进?
- 快速排序不适用于大型数组
- 快速排序;分段错误,但找不到位置?
- 快速排序函数在快速排序算法中如何工作?
- 3路随机快速排序分区功能
- 在最坏的情况下试验快速排序.它运行良好,但在最坏的情况下发生未知错误.我想
- 当给出预先排序的输入时,为什么我的快速排序实现很慢
- 当中间元素选择为枢轴时,快速排序C 不起作用
- 函数来选择用于快速排序的枢轴
- 当选择最左侧或最右侧的元素作为枢轴时,快速排序显然采用 O(n^2)