Solving Huffman tree and its coding output in C language

Keywords: C data structure linked list

target

Given a set of weights, a Huffman tree is obtained according to the weights, and the Huffman code of leaf nodes is output in the order of middle order traversal.

analysis

Firstly, the solution process of Huffman tree is reviewed:

  1. Take the smallest two X and Y in the weights, take these two weights as leaf nodes, and generate a parent node with weights of x+y;
  2. Delete X and Y from the weight group, add x+y to enter the weight group;
  3. Loop until there is only one element left in the weight group, which is the weight of the root node.

An important point is that we want the input weights to be in order and keep them in order at all times. Therefore, we choose the linked list to store the weights and sort them in order every time we insert them. Next, we can complete the construction of Huffman tree as long as we implement the above steps with code;

So how to get the Huffman code of leaf nodes?

Consider using recursion to assign a code to each node and store it in the tree node.

code implementation

Definition and initialization of tree nodes and linked list nodes

struct node
{
    int weight, idx;
    struct node *parent, *lchild, *rchild;
    char *code;
};

struct linknode
{
    int info;
    struct linknode *next;
    struct node *tree;
};
typedef struct linknode *Plink;
typedef struct node *Ptree;

Ptree createNULLtree()
{
    Ptree head = (Ptree)malloc(sizeof(struct node));
    if (head == NULL)
        printf("fail to create tree node!\n");
    head->parent = NULL;
    head->lchild = NULL;
    head->rchild = NULL;
    head->idx = 0;
    head->code = (char *)malloc(sizeof(char) * 10);
    return head;
}

Plink createNULLlink()
{
    Plink head = (Plink)malloc(sizeof(struct linknode));
    if (head == NULL)
        printf("fail to create link node!\n");
    head->next = NULL;
    head->tree = NULL;
    return head;
}

The tree node contains pointers to the parent node and the child node, weights, and stored codes and code length indexes idx;

The linked list node contains the weight size info, the next pointer to the next node and the tree pointer to the tree node corresponding to the weight.

Some tool functions

void insertwithorder(Plink head, int x, Ptree tree)
{
    Plink cur = head->next, last = head;
    if (tree == NULL)
        tree = createNULLtree();
    tree->weight = x;
    while (cur != NULL)
    {
        if (x <= cur->info)
        {
            last->next = createNULLlink();
            last->next->info = x;
            last->next->tree = tree;
            last->next->next = cur;
            return;
        }
        last = cur;
        cur = cur->next;
    }
    last->next = createNULLlink();
    last->next->info = x;
    last->next->tree = tree;
    last->next->next = cur;
}

Insert the data into the linked list in order. It is convenient to insert and delete small data

int is_over(Plink head)
{
    if (head->next->next == NULL)
        return 1;
    return 0;
}

Judge whether the program should be ended. When there is only one data left in the linked list, it will end

void LDR(Ptree head)
{
    if (head == NULL)
        return;
    LDR(head->lchild);
    visitleaf(head);
    LDR(head->rchild);
}

Medium order traversal

void visitleaf(Ptree head)
{
    if (head->lchild == NULL && head->rchild == NULL)
        printf("%d %s\n", head->weight, head->code);
}

Print only leaf node information

Generate binary tree

Use two weights to create a binary tree, and the weight of the root node is the sum of the two weights;

In the implementation process, not only the weight information of linked list nodes is required, so there is no separate function to realize this function;

The general process is as follows:

  1. Obtain two weights and their tree nodes;
  2. Generate a tree node whose weight is the sum of it;
  3. Take the new tree node as the parent node to connect the three nodes;
  4. The weights after summation are inserted into the linked list in order;
  5. Use recursion until there is only one element left in the linked list;
  6. So far, the root node of Huffman tree is obtained;
void createBiTree(Plink Link)
{
    if (is_over(Link))
        return;
    int nums[2]; //Store two weights
    Plink temp = Link->next;
    Ptree p = createNULLtree(), lch, rch;
    nums[0] = temp->info;
    lch = temp->tree;
    Link->next = temp->next;
    free(temp);
    temp = Link->next;
    nums[1] = temp->info;
    rch = temp->tree;
    Link->next = temp->next;
    free(temp);
    p->weight = nums[0] + nums[1];
    p->lchild = lch;
    p->rchild = rch;
    lch->weight = nums[0];
    rch->weight = nums[1];
    lch->parent = p;
    rch->parent = p;
    insertwithorder(Link, p->weight, p);
    createBiTree(Link);
}

Huffman coding

void encode(Ptree head, char info)
{
    if (head == NULL)
        return;
    if (head->parent != NULL)
    {
        strcpy(head->code, head->parent->code);
        head->idx = strlen(head->code);
    }
    head->code[head->idx++] = info;
    head->code[head->idx] = '\0';
    encode(head->lchild, '0');
    encode(head->rchild, '1');
}

The encode function receives the tree node and a character variable, the left subtree receives' 0 ', the right subtree receives' 1', and each tree node copies the code information of the parent node. In this way, the encoding is completed recursively.

Main function

int main()
{
    int num, temp;
    Plink linkhead = createNULLlink();
    scanf("%d", &num);
    for (int i = 0; i < num; i++)
    {
        scanf("%d", &temp);
        insertwithorder(linkhead, temp, NULL);
    }
    createBiTree(linkhead);
    Ptree treehead = linkhead->next->tree;
    if (treehead == NULL)
        printf("wrong!");
    encode(treehead, '\0');
    LDR(treehead);
    return 0;
}

So far, the title requirements have been completed.

All codes

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

struct node
{
    int weight, idx;
    struct node *parent, *lchild, *rchild;
    char *code;
};

struct linknode
{
    int info;
    struct linknode *next;
    struct node *tree;
};
typedef struct linknode *Plink;
typedef struct node *Ptree;

Ptree createNULLtree()
{
    Ptree head = (Ptree)malloc(sizeof(struct node));
    if (head == NULL)
        printf("create tree wrongly!\n");
    head->parent = NULL;
    head->lchild = NULL;
    head->rchild = NULL;
    head->idx = 0;
    head->code = (char *)malloc(sizeof(char) * 10);
    return head;
}

Plink createNULLlink()
{
    Plink head = (Plink)malloc(sizeof(struct linknode));
    if (head == NULL)
        printf("create link wrongly!\n");
    head->next = NULL;
    return head;
}

void insertwithorder(Plink head, int x, Ptree tree)
{
    Plink cur = head->next, last = head;
    if (tree == NULL)
        tree = createNULLtree();
    tree->weight = x;
    while (cur != NULL)
    {
        if (x <= cur->info)
        {
            last->next = createNULLlink();
            last->next->info = x;
            last->next->tree = tree;
            last->next->next = cur;
            return;
        }
        last = cur;
        cur = cur->next;
    }
    last->next = createNULLlink();
    last->next->info = x;
    last->next->tree = tree;
    last->next->next = cur;
}

int is_over(Plink head)
{
    if (head->next->next == NULL)
        return 1;
    return 0;
}

void createBiTree(Plink Link)
{
    if (is_over(Link))
        return;
    int nums[2];
    Plink temp = Link->next;
    Ptree p = createNULLtree(), lch, rch;
    nums[0] = temp->info;
    lch = temp->tree;
    Link->next = temp->next;
    free(temp);
    temp = Link->next;
    nums[1] = temp->info;
    rch = temp->tree;
    Link->next = temp->next;
    free(temp);
    p->weight = nums[0] + nums[1];
    p->lchild = lch;
    p->rchild = rch;
    lch->weight = nums[0];
    rch->weight = nums[1];
    lch->parent = p;
    rch->parent = p;
    insertwithorder(Link, p->weight, p);
    createBiTree(Link);
}

void encode(Ptree head, char info)
{
    if (head == NULL)
        return;
    if (head->parent != NULL)
    {
        strcpy(head->code, head->parent->code);
        head->idx = strlen(head->code);
    }
    head->code[head->idx++] = info;
    head->code[head->idx] = '\0';
    encode(head->lchild, '0');
    encode(head->rchild, '1');
}

void visitleaf(Ptree head)
{
    if (head->lchild == NULL && head->rchild == NULL)
        printf("%d %s\n", head->weight, head->code);
}

void LDR(Ptree head)
{
    if (head == NULL)
        return;
    LDR(head->lchild);
    visitleaf(head);
    LDR(head->rchild);
}

int main()
{
    int num, temp;
    Plink linkhead = createNULLlink();
    scanf("%d", &num);
    for (int i = 0; i < num; i++)
    {
        scanf("%d", &temp);
        insertwithorder(linkhead, temp, NULL);
    }
    createBiTree(linkhead);
    Ptree treehead = linkhead->next->tree;
    if (treehead == NULL)
        printf("wrong!");
    encode(treehead, '\0');
    LDR(treehead);
    return 0;
}

Posted by zz50 on Tue, 26 Oct 2021 01:28:02 -0700