zoukankan      html  css  js  c++  java
  • 哈夫曼编码的实现

      c语言可以说是一门让人既爱又恨的语言,其效率是众所周知的,但其出现的bug也是大名鼎鼎。对于高手来说,它是多么优雅,可是对门外汉而言,可以掐着指头一年一年数着啥时候能入门。或许很多人不同意这句话,可在愚钝的我身上是适得其所。最近学习c语言,通过实现一些数据结构练手,为一些bug恼火过,也为解决一些bug而拍案而起。没怎么写过博客,写得不好敬请大家谅解。下面分享一下哈夫曼编码过程。最后附上代码。

      首先声明代码有bug,当输入的字符串只含一种字符时发生异常。本来想修正这个问题的,但这两天写累了,想歇歇。如果有高手其中不足,小的不胜感激。废话不多说,步入正题吧。

      哈夫曼编码思路比较明了,就是每次根据最小的两个节点(每次找到最小权值节点时都要马上删掉该节点)生成新的根节点,根节点的权重是这两个节点权重之和,然后把新生成的根节点放进节点堆里,待下一轮筛选选择最小值,直到节点堆里只剩下一个节点,也就是哈夫曼树的树根啦。我的实现思路是,为输入的每一种字符统计其出现的次数作为权重做成链表,然后根据链表生成哈夫曼树,接着根据构造好的哈夫曼树进行编码。到这里就可以设计数据结构了,数据结构设计如下:

    View Code
     1 typedef struct tNode {
    2 char ch;
    3 int weight;
    4 struct tNode *left;//左孩子
    5 struct tNode *right;//右孩子
    6 } tnode;
    7
    8 typedef struct cNode {
    9 char ch;
    10 int count;
    11 struct cNode *next;
    12 tnode *tree;//指向当前节点的左子树的跟节点
    13 } clist;
    14
    15 typedef struct endeNode {
    16 char ch;
    17 char code[20];
    18 struct endeNode *next;
    19 } codelist;

      接下来一步就是对输入字符进行统计,构建单链表:

    View Code
     1 /**************************************************
    2 Description:将字符添加进链表里(出现相同字符则不用新建节点,仅仅更改该字符出现的次数即可)
    3 **************************************************/
    4 void
    5 pull_in_list(char in_string[])
    6 {
    7 int i;
    8 clist **link;
    9 clist *current;
    10 clist *new_node;
    11 char ch;
    12 int exist;//判断字符是否已经存在,0表示不存在,1表示存在
    13
    14 char_count = strlen(in_string);
    15
    16 for(i = 0; (ch = in_string[i]) != '\0'; i += 1)
    17 {
    18 char_mount += 1;
    19 exist = 0;
    20 link = &clistp;
    21 while((current = *link) != NULL)
    22 {
    23 link = &current->next;
    24 if(current->ch == ch)
    25 {
    26 current->count += 1;
    27 exist = 1;
    28 continue;
    29 }
    30 }
    31
    32 //in_string += 1;
    33 if(exist == 1)
    34 {
    35 continue;
    36 }
    37
    38 new_node = (clist *)malloc(sizeof(clist));
    39 assert(new_node != NULL);
    40 new_node->ch = ch;
    41 new_node->count = 1;
    42 new_node->next = NULL;
    43 new_node->tree = NULL;
    44
    45 *link = new_node;
    46 }
    47
    48 current = clistp;
    49 char_num = count_rest_list();
    50 printf("各个字符出现的次数为:\n");
    51 while(current != NULL)
    52 {
    53 printf("%c: %d 次\t", current->ch, current->count);
    54 current = current->next;
    55 }
    56 printf("\n");
    57 }

      好了,既然链表已经创建完成,是时候构建哈夫曼树了:

    View Code
    /**************************************************
    Description:构建哈夫曼树
    *************************************************
    */
    void
    create_huffman_tree()
    {
    int min1;//链表最小值
    int min2;//链表次小值
    clist *current;//指向链表节点的指针
    clist *pre;//最小节点的前一节点
    clist *min1_l;
    clist *min2_l;
    clist **link;
    clist *temp_pre;

    clist *new_lnode;
    tnode *new_tnode;
    tnode *left;
    tnode *right;

    while(count_rest_list() >= 2)
    {
    current = clistp;
    min1 = clistp->count;
    min1_l = clistp;
    while(current != NULL)
    {
    if(min1 > current->count)
    {
    min1 = current->count;
    temp_pre = pre;
    min1_l = pre->next;
    }
    pre = current;
    current = current->next;
    }
    //删除最小值节点
    if(min1_l == clistp)
    {
    clistp = min1_l->next;
    }
    else
    {
    temp_pre->next = min1_l->next;
    }

    current = clistp;
    min2 = clistp->count;
    min2_l = clistp;
    while(current != NULL)
    {
    if(min2 > current->count)
    {
    min2 = current->count;
    temp_pre = pre;
    min2_l = pre->next;
    }
    pre = current;
    current = current->next;
    }
    //删除次小值节点
    if(min2_l == clistp)
    {
    clistp = min2_l->next;
    }
    else
    {
    temp_pre->next = min2_l->next;
    }

    //左子树
    if(min1_l->tree == NULL)
    {
    left = (tnode *)malloc(sizeof(tnode));
    assert(left != NULL);
    left->ch = min1_l->ch;
    left->left = NULL;
    left->right = NULL;
    left->weight = min1_l->count;
    }
    else
    {
    left = min1_l->tree;
    }

    //右子树
    if(min2_l->tree == NULL)
    {
    right = (tnode *)malloc(sizeof(tnode));
    assert(right != NULL);
    right->ch = min2_l->ch;
    right->left = NULL;
    right->right = NULL;
    right->weight = min2_l->count;
    }
    else
    {
    right = min2_l->tree;
    }

    //生成新的树根节点
    new_tnode = (tnode *)malloc(sizeof(tnode));
    assert(new_tnode != NULL);
    new_tnode->ch = ' ';
    new_tnode->left = left;
    new_tnode->right = right;
    new_tnode->weight = left->weight + right->weight;

    //生成新的链表节点
    new_lnode = (clist *)malloc(sizeof(clist));
    assert(new_lnode != NULL);
    new_lnode->ch = new_tnode->ch;
    new_lnode->count = new_tnode->weight;
    new_lnode->next = NULL;
    new_lnode->tree = new_tnode;

    //将新生成的链表节点添加到链表中
    link = &clistp;
    while((current = *link) != NULL)
    {
    link = &current->next;
    }
    *link = new_lnode;
    free(min1_l);
    free(min2_l);
    }
    huff_tree = new_tnode;
    }

      万事俱备,只欠东风啦,最后一部当然是根据哈夫曼树进行哈夫曼编码了:

    View Code
    /**************************************************
    Description:实现哈夫曼编码(递归遍历树)
    *************************************************
    */
    void
    encoding(tnode *bt)
    {
    codelist *new_node;
    codelist *current;
    codelist **link;

    if(bt->left == NULL && bt->right == NULL)
    {
    int i;
    new_node = (codelist *)malloc(sizeof(codelist));
    assert(new_node != NULL);
    new_node->ch = bt->ch;
    for(i = 0; i < strlen(stack); i += 1)
    {
    new_node->code[i] = stack[i];
    }
    new_node->code[i] = '\0';
    new_node ->next = NULL;

    //将新生成的编码节点添加进链表中
    link = &head;
    while((current = *link) != NULL)
    {
    link = &current->next;
    }
    *link = new_node;
    //init_stack();
    }
    else
    {
    if(bt->left != NULL)
    {
    stack[++top] = '0';
    encoding(bt->left);
    stack[top] = '\0';
    top -= 1;
    }
    if(bt->right != NULL)
    {
    stack[++top] = '1';
    encoding(bt->right);
    stack[top] = '\0';
    top -= 1;
    }
    }
    }

      刚接触时间不长,很多问题都欠缺考虑,欢迎各位大神指正,谢谢。下面附上源码

      https://files.cnblogs.com/hwzhong20/HuffmanCoding.rar

  • 相关阅读:
    python数据类型
    集合(set)内置方法
    python第三天
    剑指offer-什么是1G/2G/3G/4G/5G
    经典交换实验-二层交换机实现pc隔离&vlan通信
    linux运维神器-htop&mtr
    三分钟速学linux-进程管理命令
    三分钟速学文件权限管理
    三分钟速学网卡管理配置-nmcli命令
    三分钟速学linux-centos/redhat常见包管理器
  • 原文地址:https://www.cnblogs.com/hwzhong20/p/2408810.html
Copyright © 2011-2022 走看看