【问题标题】:Pair-wise difference using recursion使用递归的成对差异
【发布时间】:2019-04-24 07:30:42
【问题描述】:

我被要求将这个伪代码翻译成 C 程序:

rep := 0
while A not empty:
    B := []
    for x in A, y in A:
        if x != y: append absolute_value(x - y) to B
    A := B
    rep := rep + 1

我最终得到了这个:

int iterateIt(int a_count, int* a) {
    unsigned long long i, j, k;
    unsigned long long count = a_count;

    for( i = 1 ; i < a_count ; i++ )
        count *= count-1;

    int *b = (int *) malloc(count * sizeof(int));
    count = 0;
    k = 0;
    for( i = 0 ; i < a_count ; i++ ){
        for( j = i ; j < a_count ; j++ ){
            if(a[i] != a[j]){
                b[k] = abs(a[i] - a[j]);
                k++;
            }
        }
    }

    if( k > 0){
        return 1 + iterateIt(k, b);
    }
    free(b);
    return 1;
}

我使用递归来返回算法的迭代次数。实际上,我取 A 的任何两个不同对象之间的差异,并将绝对值放在 B 中,我会在 B 上重复。 对于简单的输入,我得到了正确的结果,但我不明白为什么输入如下: 161 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 3276841 352 9483 50000 (第一个数字是A的元素个数)

我收到分段错误错误。

感谢您的帮助

【问题讨论】:

  • 你为什么要把count *= count-1;放在一个循环中?它计算什么?
  • 你没有测试malloc()的返回值。我的猜测是,您正在计算 count 中的一个巨大甚至负数(因为溢出)值,因此 malloc() 失败,然后您尝试写入生成的空指针。
  • 您使用 IDE 吗?它有调试器吗?你知道怎么用吗?它是您最好的朋友,可以让您轻松解决此类问题,而无需询问我们

标签: c arrays recursion segmentation-fault


【解决方案1】:

我认为您的count 是错误的。你的第二次迭代已经很了不起了。

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

size_t total_allocated = 0;

int iterateIt(int a_count, int* a) {
    unsigned long long i, j, k;
    unsigned long long count = a_count;

    for( i = 1 ; i < a_count ; i++ )
        count *= count-1;

    size_t size = count * sizeof(int);
    printf("Allocating %llu ints: %llu bytes\n", count, (unsigned long long)size);
    total_allocated += size;
    printf("Total allocated: %llu bytes\n", (unsigned long long)total_allocated);
    int *b = (int *) malloc(count * sizeof(int));
    count = 0;
    k = 0;
    for( i = 0 ; i < a_count ; i++ ){
        for( j = i ; j < a_count ; j++ ){
            if(a[i] != a[j]){
                b[k] = abs(a[i] - a[j]);
                k++;
            }
        }
    }

    if( k > 0){
        return 1 + iterateIt(k, b);
    }
    free(b);
    return 1;
}

int main (void)
{
    iterateIt(4, (int[4]){1,352,9483,50000});
    return 0;
}

结果:

Allocating 17292 ints: 69168 bytes
Total allocated: 69168 bytes
Allocating 12550317587327992670 ints: 13307782201892867448 bytes
Total allocated: 13307782201892936616 bytes

【讨论】:

    【解决方案2】:

    首先考虑这一行:

    return 1 + iterateIt(k, b);
    

    b 数组永远不会在此 return 上被释放,但如果 k 为零,它会释放。让我们重写这段代码来清理一下:

    #include <stdio.h>
    #include <stdlib.h>
    
    unsigned iterateIt(size_t a_count, int *a) {
    
        unsigned rep = 1;
    
        int *b = calloc(a_count * a_count, sizeof(int));
    
        size_t k = 0;
    
        for (size_t i = 0; i < a_count; i++) {
            for (size_t j = i + 1; j < a_count; j++) {
                if (a[i] != a[j]) {
                    b[k++] = abs(a[i] - a[j]);
                }
            }
        }
    
        if (k > 0) {
            rep += iterateIt(k, b);
        }
    
        free(b);
    
        return rep;
    }
    
    int main() {
    
        int x[] = {1, 324, 54};
    
        printf("%u\n", iterateIt(sizeof(x) / sizeof(int), x));
    
        return 0;
    }
    

    观察a_count的值,程序尝试分配过多内存失败。

    更新

    由于矩阵的两半最终相同,我修复了上述代码以执行 OP 所做的操作,只处理矩阵的 1/2,即 ji + 1 开始,因为两半最终相同.我也忽略了对角线,因为它总是零。然后代码完成了我的示例代码中的三个数字,但是当我将数组增加到四个值时再次爆炸。

    我相信 OP 解决方案的递归性质是优雅的并且不是问题,但只是为了确认,这是一个无法执行的迭代解决方案,而不是由于缺少堆栈内存:

    unsigned iterateIt(size_t a_count, int *a) {
    
        unsigned rep = 1;
    
        bool first_time = true;
    
        while (true) {
    
            int *b = calloc((a_count * a_count) / 2, sizeof(int));
    
            if (b == NULL) {
                perror("calloc failed!");
                exit(1);
            }
    
            size_t b_count = 0;
    
            for (size_t i = 0; i < a_count; i++) {
                for (size_t j = i + 1; j < a_count; j++) {
                    if (a[i] != a[j]) {
                        b[b_count ++] = abs(a[i] - a[j]);
                    }
                }
            }
    
            if (b_count == 0) {
                free(b);
                break;
            }
    
            if (first_time) {
                first_time = false;
            } else {
                free(a);
            }
    
            a = b;
            a_count = b_count;
    
            rep++;
        }
    
        return rep;
    }
    

    【讨论】:

    • 收敛是肯定存在的:在每一轮,最大值都会减小。不过,我看不出采用递归方法的理由。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 2017-12-05
    • 2014-03-30
    • 2016-09-12
    • 1970-01-01
    相关资源
    最近更新 更多