问题描述
我们应该将每种类型的速度与10000个输入进行比较。它们全部都是自己工作的,但是当我将它们添加到程序中时,我认为合并排序可能会占用大量空间,因此一旦到达unhandled exception: StackOverflow
,我总会得到quicksort
。有谁知道这个问题的解决方案,也许可以使合并排序不占用很多空间(如果这是问题所在)?具体来说,该异常会抛出在quicksort
的分区函数中。
#include <iostream>
#include <fstream>
#include <ctime>
using namespace std;
void merge(int arr[],int l,int m,int r) {
int i,j,k;
int n1 = m - l + 1;
int n2 = r - m;
int *L = new int[n1];
int *R = new int[n2];
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int arr[],int r) {
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(arr,l,m);
mergeSort(arr,m + 1,r);
merge(arr,m,r);
}
}
int partition(int arr[],int start,int end) { //start is 0 and end is counter-1
int pivot = start; //remember start here
int imp = arr[end];
for (int i = start; i < end; i++) { //remember this is start and end;
if (arr[i] <= imp) {
int temp = arr[i];
arr[i] = arr[pivot];
arr[pivot] = temp;
pivot++;
}
}
int p = arr[pivot];
arr[pivot] = arr[end];
arr[end] = p;
return pivot;
}
void quicksort(int arr[],int end) {
if (start < end) {
int index = partition(arr,start,end);
quicksort(arr,index - 1);
quicksort(arr,index + 1,end);
}
}
int main() {
clock_t timereq;
double time_taken;
ifstream in("input3.txt");
int size;
in >> size;
int num;
int *arrq = new int[size];
int i = 0;
while (!in.eof()) {
in >> num;
arrq[i] = num;
i++;
}
timereq = clock();
mergeSort(arrq,size-1);
timereq = clock() - timereq;
time_taken = double(timereq) / CLOCKS_PER_SEC; /// double(CLOCKS_PER_SEC);
cout << time_taken << endl;
timereq = clock();
quicksort(arrq,size-1);
timereq = clock() - timereq;
time_taken = double(timereq) / CLOCKS_PER_SEC; /// double(CLOCKS_PER_SEC);
cout << time_taken << endl;
for (i = 0; i < size; i++) {
cout << arrq[i] << endl;
}
}
例如,输入看起来像这样:值的数量,然后是值:
8
3 1 4 1 5 9 2 6
解决方法
quicksort的问题在于其更糟的情况:
- 如果分区函数未将数据集划分为平衡的一半,则复杂度可以达到 O(N 2 ),而不是平均的 O(N)。 log(N))。
- 在您的情况下,最坏的情况发生在列表已经排序时:枢轴将数组分为
N-1
和1
部分,导致递归发生N
次,可能对于默认的堆栈深度来说太大了。 - 您的基准测试中有一个逻辑错误,每次都会发生这种最坏的情况:您测量
mergeSort()
对arrq
广告进行排序的时间,然后对{{1} }在同一数组上,只是按quicksort
排序。您应该复制原始数组并将其传递给mergeSort
,但还必须修复quicksort
以避免此堆栈溢出。
您可以通过更改quicksort
函数以在较小的一半上递归并在较大的一半上进行迭代来解决此问题:
quicksort
这应该解决堆栈溢出错误,但不会降低时间复杂度。您需要为此更改分区功能,例如,如果默认选择会导致病理性分裂,则可以通过随机选择枢轴值来实现。
,您应该真正遵循上述注释中的建议,并通过使用stack
数据结构重新设计代码来直接解决问题的根源(有限的堆栈大小),以便专门避免内存消耗递归。
但是,原则上您也可以偷工减料,并采用更脏,更快捷的解决方案:只需在编译器中添加标志,即可增加堆栈的大小。
如果使用 gcc ,则可以通过从提示进行编译来插入-Wl,--stack,<size>
键来完成此操作。
上方的<size>
键可以大于您当前堆栈的大小,例如-Wl,1000000000
(9个零)。
如果您使用的是IDE,我碰巧知道如何在 Codeblocks 上执行此操作:转到Settings-> Compiler-> Global Compiler Settings-> Linker Settings->在上面添加行在其他链接器选项字段下。
另请参阅stackoverflow: How to increase stack size when compiling a C++ program using MinGW compiler