【问题标题】:Segmentation fault in bucket sort + insertion sort algorithm桶排序+插入排序算法中的分段错误
【发布时间】:2017-09-10 14:25:01
【问题描述】:

我想知道为什么我为桶排序实现的这个算法会导致分段错误。似乎实现中的所有内容都运行良好,但可能有一些变量 n 应该是 n+1 或其他;我在弄清楚这一点时遇到了一些困难。

我是按照this video中描述的来实现的。

#include <stdio.h>
#include <stdlib.h>

void insertion(int * array, int n){
    // insertion sort
    int i = 1, j = 0, temp;
    while(i < n){
        j = i;
        while(j > 0 && array[j-1] > array[j]){
            temp = array[j-1];
            array[j-1] = array[j];
            array[j] = temp;
            --j;
        }
        ++i;
    }
}

void bucket(int * array, int n){
    int max,i,j,k,size, div, pos;
    int ** buckets, *bucket_position;

    //Find maximum value in array
    max = array[0];
    for(i=0;i<n;++i) if( max < array[i] ) max = array[i];

    //Determine amount of buckets and creates them
    size = max / n;
    buckets = (int**) malloc(sizeof(int*) * size);
    for(i=0;i<size;++i){
        buckets[i] = (int*) malloc(sizeof(int) * max);
    }
    bucket_position = (int*) malloc(sizeof(int) * size);
    for(i=0;i<size;++i) bucket_position[i] = 0;

    //Copy array values into the buckets
    div = (max+1) / size;
    if( (max+1) % size ) ++div;
    for(i=0;i<n;++i){
        pos = array[i] / div;
        buckets[pos][bucket_position[pos]] = array[i];
        ++bucket_position[pos];
    }

    //Take values out of the buckets into the array
    k = 0;  
    for(i=0;i<size;++i){
        for(j=0;j<=bucket_position[i];++j){
            array[k] = buckets[i][j];
            ++k;
        }
    }

    //Do insertion sort over the array
    insertion(array,n);
}

int main(){
    int array[5] = {24354,95023,439052,934851};
    int n = 5;
    bucket(array,n);
    return 0;
}

程序输出是分段错误而不是排序数组。

【问题讨论】:

  • 调试器........
  • 程序收到信号SIGSEGV,分段错误。存储桶中的 0x0804868b (array=0xbffff1a8, n=5) at test.c:41 41 buckets[pos][bucket_position[pos]] = array[i]; (gdb)
  • 由于这发生在i &lt;= 0 &lt; n 的循环中,您应该查看pos,这可能超出了范围。 (您可以在 gdb 中使用 print pos 或仅使用 p pos。)
  • @Ruan 感谢调试。您应该在该行上设置断点并检查索引“pos”和“i”的值。
  • 您创建了 186970 个存储桶,每个存储桶可容纳 934851 个整数,所有这些都用于对大小为 5 的数组进行排序。有点矫枉过正,你不觉得吗? :)

标签: c algorithm sorting


【解决方案1】:

您想对包含n == 5 元素的数组进行排序,其最大值为:

max == 934851

然后你计算桶数:

size = max / n == 186970

现在您尝试为 186970 个存储桶分配内存,每个存储桶可容纳 934851 个元素:

buckets = (int**) malloc(sizeof(int*) * size);

for (i = 0; i < size; ++i) {
    buckets[i] = (int*) malloc(sizeof(int) * max);
}

这大约是 651 GB。有了这么多的大分配,系统很可能无法提供更多的内存。因此,您应该检查从malloc 返回的指针是否为NULL。这就是发生的事情:您的数组索引是合法的,但动态分配的数组是NULL

当然,您不需要那么多内存来对五个元素进行排序。对于这么小的数组,您根本不需要使用存储桶;立即使用插入排序。

对于较大的数组,桶的数量基于元素的数量,而不是最大值。在最坏的情况下,所有元素都进入一个存储桶,然后该存储桶将包含n 元素。所以你也不需要max来确定这里的大小。

但是,您应该使用您的程序没有的 maxmin 来计算存储桶索引:

index = (a[i] - min) * nbuckets / (max + 1 - min)

注意这里可能的算术溢出。 (+ 1确保最大元素不会得到无效索引n。)

【讨论】:

    【解决方案2】:

    这段代码

    k = 0;  
    for(i=0;i<size;++i){
        for(j=0;j<=bucket_position[i];++j){
            array[k] = buckets[i][j];
            ++k;
        }
    }
    

    是个问题。

    您将多次增加k,从而在array 之外写入。请记住,k 的有效范围仅为 0 到 4。

    代替

    for(j=0;j<=bucket_position[i];++j){
            ^^^^
    

    也许你想要

    for(j=0;j<bucket_position[i];++j){
            ^^^
    

    &lt; 而不是 &lt;=,这样您就不会在每个循环中增加 k

    【讨论】:

    • @Ruan - 好吧,对我来说,将&lt;= 更改为&lt; 时不再崩溃,请参阅ideone.com/J9b8ar
    • gcc (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406 因此链接上的代码出现分段错误而崩溃
    • @Ruan - 那么很可能是内存分配问题。您可以减少输入值以减少内存需求。但是,重新考虑您的设计可能会更好,因为您使用的内存比需要的多得多。仍然 - &lt;= 一定是一个错误
    • &lt;= 是一个错误。 &lt; 是正确的。我实现了&lt; 加上@M Oehm 解决方案,现在它可以工作了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多