当输入大小足够大时,合并排序崩溃

时间:2016-06-05 20:49:19

标签: c++ debugging mergesort

我有一系列不断增长的输入值,我想分析它的运行时间。

int main(){
    srand(time(NULL));  //initialize random num generator with time(NULL) as seed
    int size_arr[7] = {1000, 10000, 25000, 50000, 100000, 150000, 200000};
//  int size_arr[6] = {1000, 10000, 25000, 50000, 100000, 129992};
    int size = (sizeof(size_arr)/sizeof(int));

当传递使用以下内容创建的数组时,输入数组int size_arr[7]适用于我的Quicksort和插入排序实现:

for(int k = 0; k < size; k++){
            double sort_arr[size_arr[k]];
            for(unsigned int l = 0; l < (sizeof(sort_arr)/sizeof(double)); l++){
                sort_arr[l] = random_double(100.00, 1000.00);
            }
}

使用此处生成的double值:

double random_double(double min, double max){
    return (max - min) * ((double)rand() / (double)RAND_MAX) + min;
}

但是,当我通过合并排序函数运行数组时:

//merge sort algorithm
void merge_sort(double *A, int p, int r){

    if(p < r){                      //stopping condition
        int mid = floor((p + r) / 2);   //find array midpoint
        merge_sort(A, p, mid);      //recursively divide array
        merge_sort(A, mid+1, r);
//      merge(A, p, mid, r);        //merge (sort) sub-arrays
        merge_sort_merge(A, p, mid, r);
    }
}

void merge_sort_merge(double *A, int left, int mid, int right){
    double tmp[right];
    int l = left, m = mid+1, sort_index = left;
    for(int i = left; i <= right; i++){
        tmp[i] = A[i];
    }
    while(l <= mid && m <= right){
        if(tmp[l] <= tmp[m]){
            A[sort_index] = tmp[l];
            l++;
        }else{
            A[sort_index] = tmp[m];
            m++;
        }
        sort_index++;
    }
    while(l <= mid){
        A[sort_index] = tmp[l];
        sort_index++;
        l++;
    }
}

当输入大小正好是129992时(我已经使用int size_arr[6]测试它),它会崩溃。

完整代码如下:

#include <iostream>
#include <array>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <exception>

void merge_sort(double *A, int p, int r);
void merge(double *A, int p, int q, int r);
double random_double(double min, double max);

int main(){
    srand(time(NULL));  //initialize random num generator with time(NULL) as seed
    int size_arr[7] = {1000, 10000, 25000, 50000, 100000, 150000, 200000};
//  int size_arr[6] = {1000, 10000, 25000, 50000, 100000, 129992};
    int size = (sizeof(size_arr)/sizeof(int));

    std::cout << "Merge Sort:" << std::endl;
        for(int k = 0; k < size; k++){
            double sort_arr[size_arr[k]];
            for(unsigned int l = 0; l < (sizeof(sort_arr)/sizeof(double)); l++){
                sort_arr[l] = random_double(100.00, 1000.00);
            }
            clock_t begin = clock();
            try{
                merge_sort(sort_arr, 0, (sizeof(sort_arr)/sizeof(double)));
            }catch(const std::runtime_error& re){
                std::cerr << "Runtime error: " << re.what() << std::endl;
            }catch(const std::exception &exc){
                std::cerr << exc.what();
            }catch(...){
                std::cerr << "Fuck" << std::endl;
            }
            clock_t end = clock();
            std::cout << "n = " << size_arr[k] << '\t' << (end - begin) << std::endl;
        }

    return 0;
}

//merge sort algorithm
void merge_sort(double *A, int p, int r){

    if(p < r){                      //stopping condition
        int mid = floor((p + r) / 2);   //find array midpoint
        merge_sort(A, p, mid);      //recursively divide array
        merge_sort(A, mid+1, r);
//      merge(A, p, mid, r);        //merge (sort) sub-arrays
        merge_sort_merge(A, p, mid, r);
    }
}

void merge_sort_merge(double *A, int left, int mid, int right){
    double tmp[right];
    int l = left, m = mid+1, sort_index = left;
    for(int i = left; i <= right; i++){
        tmp[i] = A[i];
    }
    while(l <= mid && m <= right){
        if(tmp[l] <= tmp[m]){
            A[sort_index] = tmp[l];
            l++;
        }else{
            A[sort_index] = tmp[m];
            m++;
        }
        sort_index++;
    }
    while(l <= mid){
        A[sort_index] = tmp[l];
        sort_index++;
        l++;
    }
}

double random_double(double min, double max){
    return (max - min) * ((double)rand() / (double)RAND_MAX) + min;
}

我已尝试捕获异常(它没有抛出任何异常),使用VS JIT调试器但无法从中获取任何有用信息,反汇编如下(箭头指向错误):

00000000004100D0  cmp         rax,1000h  
00000000004100D6  ja          00000000004100BF  
00000000004100D8  sub         rcx,rax  
00000000004100DB  or          qword ptr [rcx],0 <---- 
00000000004100DF  pop         rax  
00000000004100E0  pop         rcx 

似乎无法单步执行&gt; 129k递归,当我有如此大的输入大小时,如何缩小问题所在?

感谢任何帮助

1 个答案:

答案 0 :(得分:2)

size_arr[k] == 129'992时,

的大小
double sort_arr[size_arr[k]];

129'992 * sizeof(double) == 129'992 * 8 == 1'039'936。这只是1'048'576 == 1M(二进制Mega)的羞怯。

C标准没有说明存储variable length arrays的位置(C ++根本没有定义VLA),但通常它们是在堆栈上分配的。

  

使用VS JIT

意味着您使用的是Windows。 Windows上的默认堆栈大小为1MBsort_arr未使用的8640字节很容易被您的其他程序耗尽(主要是tmp merge_sort_merge sort_arr,其中std::vector的大小为spark-shell \ spark.driver.extraClassPath="/path/to/jar/spark-csv_2.11.jar" \ spark.executor.extraClassPath="spark-csv_2.11.jar" 。换句话说,你溢出了堆栈。

解决方案:不要将可变长度数组用于大型数组。 (如果您更喜欢便携式和标准兼容的程序,请不要使用VLA)。而是使用动态分配的数组(--jars)。