快速排序不排序高范围的数字
Quick Sort not sorting numbers of high range
void quickSort(vector<long>& numberList,long low, long high){
long pivot, indexLow, indexHigh, temp;
if(low<high){
pivot = low;
indexLow = low;
indexHigh = high;
while(indexLow<indexHigh){
while(numberList[indexLow] <= numberList[pivot]){
indexLow++;
}
while(numberList[indexHigh] > numberList[pivot]){
indexHigh--;
}
if(indexLow<indexHigh){
temp = numberList[indexLow];
numberList[indexLow] = numberList[indexHigh];
numberList[indexHigh] = temp;
}
}
temp = numberList[pivot];
numberList[pivot] = numberList[indexHigh];
numberList[indexHigh] = temp;
quickSort(numberList, low, indexHigh-1);
quickSort(numberList, indexHigh+1, high);
}
}
这段代码完美地排序了给定的数字列表到10000,但我尝试了100000,程序被终止,你能告诉我我做错了什么吗?
你的程序肯定有bug: http://ideone.com./W0Chni
我只对10个元素进行排序2-1-3-8-1-6-8-9-9,它在崩溃前不久以indexLow为11结束。
对不起,我的错,它工作正常。
我提示可能是堆栈溢出。您可以通过采用不同的枢轴来减轻这种可能性(无论如何都应该这样做),但是避免堆栈溢出的最佳方法是使用堆栈数据结构而不是递归:
- 将初始{low,high}推送到堆栈 在while循环中包装函数,直到堆栈为空。每次迭代都从堆栈中取出顶部{low,high}。
- 不是递归,而是将{low,high}对压入堆栈。
像这样:http://ideone.com/gwWSjV
void quickSort(std::vector<long>& numberList, long low, long high)
{
struct lh { long low; long high; };
std::vector<lh> stack;
stack.push_back(lh{low, high});
while (!stack.empty())
{
lh popped = stack.back();
stack.pop_back();
low = popped.low;
high = popped.high;
long pivot, indexLow, indexHigh, temp;
if(low<high){
pivot = low;
indexLow = low;
indexHigh = high;
while(indexLow<indexHigh){
while(numberList[indexLow] <= numberList[pivot]){
indexLow++;
}
while(numberList[indexHigh] > numberList[pivot]){
indexHigh--;
}
if(indexLow<indexHigh){
temp = numberList[indexLow];
numberList[indexLow] = numberList[indexHigh];
numberList[indexHigh] = temp;
}
}
temp = numberList[pivot];
numberList[pivot] = numberList[indexHigh];
numberList[indexHigh] = temp;
//quickSort(numberList, low, indexHigh-1);
stack.push_back(lh{low, indexHigh-1});
//quickSort(numberList, indexHigh+1, high);
stack.push_back(lh{indexHigh+1, high});
}
}
}
volil
你可以优化它,只将第二次递归压入堆栈,然后立即循环执行第一次,而不需要push/pop,但这不是一个巨大的收益。
虽然可能像其他人说的那样是堆栈溢出,但我对此表示怀疑。你的代码有一些错误,这可能会导致它访问超出数组的位置,这将(可能,虽然不能保证)提示提前终止与分割故障(或者它似乎在其他情况下工作良好,这就是为什么UB是如此糟糕)。
考虑一下:
while(numberList[indexLow] <= numberList[pivot]){
indexLow++;
}
while(numberList[indexHigh] > numberList[pivot]){
indexHigh--;
}
如果数组中的每个数字都小于或等于numberList[pivot]
怎么办?indexLow
将愉快地增加到high
之上,这很可能是数组的大小。您需要在两个循环中检查外部循环条件是否仍然存在。所以,这样做:
while (indexLow < indexHigh && numberList[indexLow] <= numberList[pivot]) {
indexLow++;
}
while (indexHigh > indexLow && numberList[indexHigh] > numberList[pivot]) {
indexHigh--;
}
确保内部循环不会使外部条件无效;如果没有这个,所有的赌注都是关于为什么你的代码破坏/不工作。
然后我们有这个:
temp = numberList[pivot];
numberList[pivot] = numberList[indexHigh];
numberList[indexHigh] = temp;
现在,如果你像我说的那样修复循环,这可能会有问题。循环可能已经停止,因为每个元素都小于或等于枢轴(在这种情况下,做这个交换操作是安全的),但是循环可能已经停止,因为indexLow
和indexHigh
碰撞了,在这种情况下,我们不知道numberList[indexLow]
是否实际上大于枢轴,或者它是否仍然小于或等于枢轴。因此,我们需要手动测试它,并可能递减indexLow
以找到与pivot交换的值:
assert(indexLow == indexHigh);
assert(indexLow > low);
if (numberList[indexLow] > numberList[pivot])
indexLow--;
assert(numberList[indexLow] <= numberList[pivot]);
temp = numberList[pivot];
numberList[pivot] = numberList[indexLow];
numberList[indexLow] = temp;
quickSort(numberList, low, indexLow-1);
quickSort(numberList, indexLow+1, high);
以下是包含这些修复的完整版本:
void quickSort(vector<long> &numberList, long low, long high) {
long pivot, indexLow, indexHigh, temp;
if (low<high) {
pivot = low;
indexLow = low;
indexHigh = high;
while (indexLow < indexHigh) {
while (indexLow < indexHigh && numberList[indexLow] <= numberList[pivot]) {
indexLow++;
}
while (indexHigh > indexLow && numberList[indexHigh] > numberList[pivot]) {
indexHigh--;
}
if (indexLow < indexHigh) {
temp = numberList[indexLow];
numberList[indexLow] = numberList[indexHigh];
numberList[indexHigh] = temp;
}
}
assert(indexLow == indexHigh);
assert(indexLow > low);
if (numberList[indexLow] > numberList[pivot])
indexLow--;
assert(numberList[indexLow] <= numberList[pivot]);
temp = numberList[pivot];
numberList[pivot] = numberList[indexLow];
numberList[indexLow] = temp;
quickSort(numberList, low, indexLow-1);
quickSort(numberList, indexLow+1, high);
}
}
请注意,此实现比通常情况下不必要地更复杂。像这样在数组中前后移动并没有得到什么好处。传统的实现更容易编写代码,更容易阅读和理解:
void quicksort_simpler(vector<long> &numberList, long low, long high) {
if (low >= high)
return;
long pivot = low;
long last = pivot;
long i;
for (i = pivot+1; i <= high; i++) {
if (numberList[i] <= numberList[pivot]) {
last++;
swap(numberList[last], numberList[i]);
}
}
swap(numberList[last], numberList[pivot]);
quicksort_simpler(numberList, low, last-1);
quicksort_simpler(numberList, last+1, high);
}
确保包含<algorithm>
以获得swap()
的声明
对于快速排序来说,选择一个好的枢轴非常重要。您正在获取第一个元素(实际上是您的low
):
pivot = low;
因此你得到了深度100000的递归,所以它的堆栈溢出
对于10^5个元素,有太多的递归例程调用,这将超出函数堆栈容量并导致堆栈溢出。就像快速排序的最坏情况(当所有元素都已经排序O(n^2)
)一样,递归关系是T(n) = T(n - 1) + Θ(n)
,这肯定会导致堆栈溢出。实际上,在最佳/平均情况下,10^5也足以导致堆栈溢出(O(n logn)
)。如果容器太大,请使用迭代方法进行快速排序。
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 如何从适合一定范围的数字中提取数字?
- 如何使用count_if计算向量中的可变数字范围
- 如何找到给定范围内除以给定数字时具有一定余数的值的数量?
- 如何按升序对输入文件中的数字进行排序,并找到它们的范围和中值
- 从(排序的)数字列表中获取数字范围
- 我应该如何使用remove_if删除两个数字范围内的元素
- C++ 如何在给定范围内将数组中的数字相加?
- 计算数字范围内特定数字的出现次数
- 为什么此范围基于语句返回一个数字太低的范围
- 编程:原理与实践 使用C++ 第 4 章演练步骤 6:关于数字范围的一般问题
- 当数字可能超出C++中特定数据类型的范围时如何处理异常?
- 随机整数仍在生成低于或高于范围的数字?
- RAND()在递归功能中产生的数字高于设定范围
- 从排序的数字数组中返回数字范围的最快方法是什么?
- 给定 N 个范围.有多少种方法可以从这些范围中获取 N 个数字,这些数字的总和达到某个值
- 更快的方法将数字从范围转换为另一个范围
- 在给定范围内数字的最大值
- 操作员支持的数字范围
- 用于大范围数字的分类