c++栈内存溢出问题

问题说明

  • 实验课测量快排时间时,用int ar[MAXSIZE+1];来创建数组,数据规模从1000-10000,而MAXSIZE的设置不能超过600 000,超过了程序就无法运行直接中断,理论上这是不应该。

  • 程序中用rand()生成随机数据,但若对数据求模rand()%100,则程序运行到中途会异常中断。

问题原因

  • int ar[MAXSIZE+1];这种创建数组的方法是在内存创建的,而内存只有2MB,里面除了数组还有其它东西,导致这种定义方式不能定义大数组。而只能通过mallocnew分配区内存。
  • 与快排时间复杂度有关,pivot是数组中间时,每次递归对半分,时间复杂度O(n),但求模之后,数据量大,而数据值只在0~100,导致数组pivot可能偏向一端,导致递归出现类似全为右节点的树,导致时间复杂度增大,递归深度加深,最终导致内存溢出。

参考文献

C/C++开大数组溢出问题_c++数组太大-CSDN博客

而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了。

posted @ 2024-03-26 13:32  faf4r  阅读(95)  评论(0)    收藏  举报