c++栈内存溢出问题
问题说明
-
实验课测量快排时间时,用
int ar[MAXSIZE+1];
来创建数组,数据规模从1000-10000
,而MAXSIZE
的设置不能超过600 000
,超过了程序就无法运行直接中断,理论上这是不应该。 -
程序中用
rand()
生成随机数据,但若对数据求模rand()%100
,则程序运行到中途会异常中断。
问题原因
int ar[MAXSIZE+1];
这种创建数组的方法是在栈
内存创建的,而栈
内存只有2MB,里面除了数组还有其它东西,导致这种定义方式不能定义大数组。而只能通过malloc
或new
分配堆
区内存。- 与快排时间复杂度有关,
pivot
是数组中间时,每次递归对半分,时间复杂度O(n),但求模之后,数据量大,而数据值只在0~100,导致数组pivot可能偏向一端,导致递归出现类似全为右节点的树,导致时间复杂度增大,递归深度加深,最终导致栈
内存溢出。
参考文献
而Stack的空间只有 2 M !也就是 210241024=2097152 字节,局部变量空间顶多放得下下 524288 个 int 类型,这也就是为什么数组直接开 100 w 大小会爆掉。
测试代码
#include <iostream>
#include <fstream>
#include <cstdlib> //rand(), crand()
#include <ctime> //srand(time(NULL))
#include <chrono> //steady_clock::now()
using namespace std::chrono; //steady_clock, duration_cast
// https://learn.microsoft.com/zh-cn/cpp/standard-library/steady-clock-struct?view=msvc-170
using namespace std;
#define MAXSIZE 400000 // 不能超过5e5
typedef struct {
int ar[MAXSIZE+1]; //ar[0]作哨兵
int length;
} SqList;
void show(SqList L) {
srand(time(NULL)); //随机种子
for (int i = 1; i <= L.length; i++)
cout << L.ar[i] << " ";
cout << endl;
}
//快速排序
void QuickSort(SqList &L, int low, int high) {
//退出递归条件
if (low >= high) { //注意可能有low大于high的情况
//当前区间就一个元素,直接返回
return;
}
//记录下当前排序的区段
int begin = low;
int end = high;
//选取第一个元素作为pivot(枢轴)
L.ar[0] = L.ar[low]; //此时low已为空,从low开始插入
bool flag = true; //记录在low插入还是在high插入,true在low插入,从high开始遍历
while (low != high) { //low high向中间靠拢,直到相等时靠到最中间
if (flag) { //!从high开始遍历,在low插入
if (L.ar[high] < L.ar[0]) { //小于哨兵,插入low
L.ar[low] = L.ar[high];
flag = false; //元素被移走了,high保持,不要移动,等着被插入
} else {
high--; //没有被移走才要让指针移动
}
} else { //!从high开始遍历,在high插入,
if (L.ar[low] > L.ar[0]) { //大于哨兵,插入high
L.ar[high] = L.ar[low];
flag = true;
} else {
low++;
}
}
}
//middle == low == high
L.ar[low] = L.ar[0]; //把哨兵填回中间
//递归排序子序列
QuickSort(L, begin, low-1);
QuickSort(L, low+1, end);
}
void random_value(SqList &L, int n) {
L.length = n;
for (int i = 1; i <= n; i++) {
L.ar[i] = rand()%100; //求模是数据规律增大时间复杂度
}
}
long exec_count(int n) {
//prepare SqList
SqList L;
random_value(L, n);
//start clock
auto start_time = steady_clock::now();
//!execution
QuickSort(L, 1, L.length);
//end clock
auto end_time = steady_clock::now();
//calculate and output time duration
auto total_time_ms = duration_cast<milliseconds>(end_time - start_time).count();
cout << "length: " << n << "\texecute time=" << total_time_ms << "ms" << endl;
return total_time_ms;
}
int main() {
long calc_time;
long ar[10000] = {0};
int count = 0;
for (int i = 1000; i <= 400000; i += 1000) {
calc_time = exec_count(i);
ar[count++] = calc_time;
}
ofstream fp("times.csv", ios::out);
fp << "scale, calc_time_in_ms" << endl;
for (int i = 0; i < count; i++) {
fp << (i+1)*1000 << ", " << ar[i] << endl;
}
fp.close();
return 0;
}
MAXSIZE和for循环的最大值同步变化,不求模就没问题,求模之后就不能到5e5了。