【问题标题】:Returning an array of structs from a recursive huffman tree C从递归霍夫曼树 C 返回结构数组
【发布时间】:2017-06-28 21:10:41
【问题描述】:

我在课堂上有一个任务,要从霍夫曼树中返回一个被击中的符号数组。 函数 getSL (仅)获得一棵霍夫曼树并返回 Symbol。 数组中的每个点都包含来自树的“叶子”的字符和 他的代码的长度(直到叶子有多少横截面)。 我的主要问题是找到我如何推进 arry 的 cnt 以使其不会过度使用 arry。 谢谢。

typedef  struct  HNode {
    char  chr;
    struct HNode *left, *right;
} HNode;

typedef  struct {
    char chr;
    int counter;
}Symbol;

这是我到现在为止所做的。

Symbol * getSL(HNode *root) {

    if (root->left == NULL && root->right == NULL) {
        Symbol* b = (Symbol*)malloc(100);
        b->counter=0;
        b->chr = root->chr;
        return b;
    }
    Symbol* a = (Symbol*)malloc(100);

    if (root->left != NULL) {
        a= getSL(root->left);
        a->counter++;
    }

    if (root->right != NULL) {
        a= getSL(root->right);
        a->counter++;
    }
    return a;
}

【问题讨论】:

  • 做一个空运行来计算。然后分配数组,然后再次运行,或者使用reallocate
  • 请用英文写,不要缩写。 ;-)
  • 顺便说一句,你有内存泄漏。
  • Symbol* b = (Symbol*)malloc(100); 很可能分配了错误的字节数(100),并且有不必要的强制转换。也许您打算写Symbol* b = malloc(sizeof *b);
  • 我知道我可能对 malloc 有问题,但这不是我问的问题。除非它能解决问题?

标签: c


【解决方案1】:

除了 malloc 问题(已参见 cmets),您还有一个基本问题:您分配了一个新结构,然后将其替换为从递归调用返回的结构。所以你丢失了之前创建的那个(实际上是内存泄漏!)。

现在最简单的变体是将您的符号转换为链表节点;那么你可以这样做:

Symbol* lastLeafFound; // probaly a function parameter!

if(!(root->left || root->right))
{
    // leaf found:
    Symbol* a = (Symbol*)malloc(sizeof(Symbol));
    a->chr = root->chr;
    a->counter = /* ... */;
    a->next = NULL;
    lastLeafFound->next = a;
    // you might return a now as last leaf found, using it in the next recursive call
}

当然,上面的代码是不完整的,但应该给你的想法......

如果你不能修改你的结构,那么你需要创建一个数组并将它传递给每个新的递归调用(最好不要使用全局变量):

void doGetSL
(
    HNode* root,
    Symbol** symbols,      // your array to be used
    unsigned int* count,   // number of symbols contained so far
    unsigned int* capacity // maximum possible symbols
)

将所有数据作为指针传递允许函数根据需要修改它们,并且它们仍然可以从外部获得......

Symbol* getSL(HNode* root)
{
    if(!root)
        return NULL;

    unsigned int count = 0;
    unsigned int capacity = 128;
    // allocate a whole array:
    Symbol* array = malloc(capacity*sizeof(Symbol));

    if(array) // malloc could fail...
    {
        doGetSL(root, &array, &count, &capacity);

        // as you cannot return the number of leaves together with
        // the array itself, you will need a sentinel:
        array[count].chr = 0;
        // obvious enough, I'd say, alternatively you could
        // set counter to 0 or -1 (or set both chr and counter) 
    }
    return array;
}

doGetSL 现在将使用上面设置的“基础设施”:

{
    if(!(root->left || root->right))
    {
        if(*count == *capacity)
        {
            // no memory left -> we need a larger array!

            // store in separate variables:
            unsigned int c = *capacity * 2;
            Symbol* s = realloc(symbols, c * sizeof(Symbol));
            // now we can check, if reallocation was successful
            // (on failure, s will be NULL!!!):
            if(s)
            {
                // OK, we can use them...
                *symbols = s; // <- need a pointer for (pointer to pointer)!
                *capacity = c;
            }
            else
            {
                // re-allocation failed!
                // -> need appropriate error handling!
            }
        }

        (*symbols)[count].chr = root->chr;
        (*symbols)[count].counter = /*...*/;
        ++*count;

    }
    else
    {
        if(root->left)
        {
            doGetSL(root->left, symbols, count, capacity);
        }
        if(root->right)
        {
            doGetSL(root->right, symbols, count, capacity);
        }
    }
}

还有一件事被忽略了:设置计数器。这很简单:在doGetSL 中添加另一个参数来指示当前深度,您可以在输入 doGetSL 时立即增加该参数,然后您可以在需要时分配此值。

如果你引入一个新的结构,你可以进一步改进上述变体(尤其是可读性):

struct SLData
{
    Symbol* symbols,      // your array to be used
    unsigned int count,   // number of symbols contained so far
    unsigned int capacity // maximum possible symbols
};

并传递这个而不是三个指针:

doGetSL(HNode*, struct SLData*, unsigned int depth);

struct SLData data = 
{
    .count = 0;
    .capacity = 128;
    .array = malloc(capacity*sizeof(Symbol));
};
if(data.array)
    doGetSL(root, &data, 0); // again passed as pointer!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多