指针算术:霍夫曼树遍历

时间:2013-11-11 22:48:30

标签: c pointers tree huffman-code

我对指针算法很困惑,我想做一个树遍历函数,但我不太确定指针算法来获取树中的远程节点。在代码中看到它会更加清晰,所以在这里。

node **root = huffman_tree(probabilities); // I can only return that as a double ptr

现在,如果我需要来自我的根节点的数据:

printf("%lf", (*root)->data);

如果我想要来自孩子们的数据:

printf("%lf", (*root)->left->data); // or (*root)->right->data

但是,如果我想进一步深入搜索,我不知道如何到达那些节点呢?

printf("%lf", (*root)->left->left->data); // thats not working

此外,对于树遍历,这不起作用:程序崩溃。

node **root = huffman_tree(probabailities);
preorder(*root);

void preorder(node *n){
if(n == NULL) return;
printf("%lf", n->data);
preorder(n->left);
preorder(n->right);

}

对于上面的示例,程序崩溃。

更新1:

似乎huffman_tree()确实返回了一个节点已损坏的树,我必须为它们做错误的内存分配。

该函数传递一组概率,然后获得如下步骤:

1)创建具有给定概率的节点(n个概率 - > n个新节点)[工作正常]

2)找到概率最低的两个节点[工作正常] 3)创建一个新节点,它是两个最低概率节点的父节点

4)分配一个新的节点概率等于它的子概率的总和

5)从步骤2)重复,直到只剩下一个无父节点

node **huffman_tree(double *probabs){


int num_of_nodes = NUM_OF_SYMBOLS;
int num = NUM_OF_SYMBOLS;

// 1) create nodes for given probabilities
node *leafs = (node*) malloc(num_of_nodes*sizeof(node));
int i;
for(i=0; i<num_of_nodes; i+=1){
    node *n = (node *) malloc(sizeof(node));
    n->probab = *(probabs + i);
    n->symbol = *(SYMBOLS + i);
    n->left = NULL;
    n->right = NULL;
    *(leafs+i) = *n;
    //free(n);
}

node **root;

while(num_of_nodes > 1){

    // 2) Find the two nodes with lowest probabilities
    node *two_mins =(node *)malloc(2*sizeof(node));
    two_mins = find_two_mins(leafs, num_of_nodes);
    node min_n1 = two_mins[0];
    node min_n2 = two_mins[1];


    // 3) Create a parent node with probability equals to sum of its children probabilities
            // add a parent node to leafs
    node *new_node = (node *) malloc(sizeof(node));
    new_node->probab = min_n1.probab + min_n2.probab;
    new_node->left = &min_n1;
    new_node->right = &min_n2;

    leafs = add_node(leafs, new_node, num);
    num += 1;
    leafs = remove_node(leafs, &min_n1, num);
    num -= 1;
    leafs = remove_node(leafs, &min_n2, num);
    num -= 1;

    num_of_nodes -= 1;

    root = &new_node;
}

return root;

函数add_node()[似乎工作正常]

node *add_node(node *nodes, node *n, int num){
nodes = realloc(nodes, (num+1)*sizeof(node));
nodes[num] = *n;
return nodes;

函数remove_node()[似乎工作正常]

node *remove_node(node *nodes, node *n, int num){
int i;
int index = 0;
for(i=0; i<num; i+=1){
    if(nodes_are_equal(nodes[i], *n)) index = i;
}

for(i=index; i<num-1; i+=1){
    nodes[i] = nodes[i+1];
}

nodes = realloc(nodes, (num-1)*sizeof(node));

return nodes;

更新2

我在huffman_tree()函数中改变了一些东西。

函数find_two_mins()不再存在,但它被另一个函数find_min()的两次调用替换,该函数一次只找到一个最小节点。此外,此函数将指针指向动态分配的节点,并在找到最小值后将其返回。

    node *root;

while(num_of_nodes > 1){

    // 2) Find two min nodes
    node *min_n1= (node *)malloc(sizeof(node));
    node*min_n2= (node *)malloc(sizeof(node));

    *min_n1= *find_min(leafs, num, min_n1);
    leafs = remove_node(leafs, min_n1, num);
    num -= 1;

    *min_n2= *find_min(leafs, num, min_n2);
    leafs = remove_node(leafs, min_n2, num);
    num -= 1;

    printf("\nTwo Min Nodes:  %lf\t%lf", min_n1->probab, min_n2->probab);
    printf("\nSum Of All: %lf", s);


    // 3) Create parent node of two min nodes

    node *new_node = (node *) malloc(sizeof(node));
    new_node->probab= min_n1->probab+ min_n2->probab;
    new_node->left = min_n1;
    new_node->right = min_n2;

    leafs = add_node(leafs, new_node, num);
    num += 1;

    free(min_n1);
    free(min_n2);

    num_of_nodes -= 1;

    root = new_node;

    printf("root=%p\n", root);
    printf("*root=%p\n", *root);
}

return root;

这是find_min()函数:

node *find_min(node *nodes, int num, node *min_node){

double min_probab = nodes[0].probab;
*min_node= nodes[0];

int i;
for(i=0; i<num; i+=1){
    if(nodes[i].probab< min_probab){
        min_probab = nodes[i].probab;
        *min_node = nodes[i];
    }
}

return min_node;

看起来问题就是这个输出:

        printf("root=%p\n", root);
    printf("*root=%p\n", *root);

因为它输出“root = 003A17F0”和“* root = 00000000”

此外,我提供了程序如何运行的屏幕截图,其中可以看到任何点的根值。 how it runs

1 个答案:

答案 0 :(得分:3)

(*root)->left->left->data是访问grand-child节点的正确方法,只要子节点不为null,并假设您的节点类似于:

struct node
{
    double data;
    struct node * left;
    struct node * right;
}

如果没有看到完整的代码,很难确定这里发生了什么。您在预订中的空检查看起来不错,所以我怀疑您必须以某种方式破坏您的一个节点,并在那里获得一个无效(但非NULL)指针。

在预先排序的空检查之后立即进行以下操作应该会使问题更加明显:

printf("processing node %p", n); fflush(stdout);
printf("  left=%p\n", n->left); fflush(stdout);
printf("  right=%p\n", n->right); fflush(stdout);

你正在寻找那些“看起来不像”其他指针的指针,特别是在它崩溃之前。

问题的最可能原因是huffman_tree本身。我怀疑你在那里有一些东西从堆栈中获取节点的地址而不是用malloc动态分配它。

根据“回答”中提供的其他信息进行修改:

您的问题可能出在find_two_mins函数中。以下代码

node *two_mins =(node *)malloc(2*sizeof(node));
two_mins = find_two_mins(leafs, num_of_nodes);
node min_n1 = two_mins[0];
node min_n2 = two_mins[1];

(正确地)动态地为节点分配内存,但是你将指向该动态内存的指针扔掉并用find_two_mins的结果替换它。

在我认为的地方周围也有其他一些内存泄漏(虽然它不会导致你的问题)。在初始循环中,

node *n = (node *) malloc(sizeof(node));

不会被释放。您正在将该结构复制到正确分配的leafs数组中,因此只需将其设为node n;

我没有进一步详细了解,所以可能会有更多问题,但请告诉我你的位置。