数据结构之赫夫曼编码

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

typedef struct
{
    unsigned int weight;/*
放权值*/
    unsigned int parent;/*
父亲结点
*/
    unsigned int lchild;/*
左孩子
*/
    unsigned int rchild;/*
右孩子
*/
}HTNode, *HuffmanTree;   /*
动态申请赫夫曼树
*/
typedef char **HuffmanCode;/*
动态分配赫夫曼表*/

void CreateHuffmanTree(HuffmanTree *HT, unsigned int *w , int n);
void Select(HuffmanTree HT, int t, int *s1, int *s2);
void HuffmanCoding(HuffmanTree HT, HuffmanCode *HC, int n);
void PrintHuffmanCode(HuffmanCode HC, unsigned int *w, int n);
int main(void)
{
    HuffmanTree HT;
    HuffmanCode HC;  
    int i, n;
    unsigned int *w;
   
    printf("
请输入叶子结点数 : ");
    scanf("%d", &n);
   
    w = (unsigned int *)malloc(n * sizeof(unsigned int));
   
    printf("
请输入各个叶子结点的权值
: /n");
    for(i = 0; i < n; i++)
    {
        scanf("%d", &w[i]);
    }
    CreateHuffmanTree(&HT, w, n);
    HuffmanCoding(HT, &HC, n);
    PrintHuffmanCode(HC, w, n);
   
    system(“pause”);
}

/*****************************
建立赫夫曼树,w存放权值,在每次
把两个小的权值相加后,在每次
select
中都能包括进去新的结点
每次父亲结点被重新赋值,不为0
在每次select中除去

*****************************/
void CreateHuffmanTree(HuffmanTree *HT, unsigned int *w , int n)
{
     int i, m;
     int s1, s2;
     char *cd;
    
     m = 2 * n - 1;                /*
总结点数*/
    
     *HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
    
     for(i = 1; i <= n; ++i, ++w)  /*
叶子结点初试化
*/
     {
         (*HT)[i].weight = *w;
         (*HT)[i].parent = 0;
         (*HT)[i].lchild = 0;
         (*HT)[i].rchild = 0;
     }
    
     for(; i <= m; ++i)
     {
         (*HT)[i].weight = 0;
         (*HT)[i].parent = 0;
         (*HT)[i].lchild = 0;
         (*HT)[i].rchild = 0;
     }
    
     for(i = n + 1; i <= m; ++i)
     {
         Select(*HT, i - 1, &s1, &s2);/*
从权值中选两个最小的
*/
         (*HT)[s1].parent = i;       /*
父亲结点都被赋值,select循环中可以除去
*/
         (*HT)[s2].parent = i;
         (*HT)[i].lchild = s1;      /*
孩子结点被赋值
*/
         (*HT)[i].rchild = s2;
         (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;/*
加后成新结点
*/
     }
}

/*寻找两个最小的结点s1, s2*/
void Select(HuffmanTree HT, int t, int *s1, int *s2)
{
     int m, n, i;
    
     m = n = 10000;/*
感觉有点取巧可以自己修改
*/
     for(i = 1; i <= t; i++)/*
遍历找两个最小的结点
*/
     {
         if(HT[i].parent == 0 /*m
n只是一个穿插的过程
*/
            && (HT[i].weight < m || HT[i].weight < n))
         {
             if(m < n)         /*
把大的除去,小的继续比较放那里
*/
             {
                 n = HT[i].weight;
                 *s2 = i;
             }
             else
             {
                 m = HT[i].weight;
                 *s1 = i;
             }
         }
     }
     if(*s1 > *s2)            /*
把小的放前面
*/
     {
         i = *s1;
         *s1 = *s2;
         *s2 = i;
     }
}

/*赫夫曼编码,放入HC*/
void HuffmanCoding(HuffmanTree HT, HuffmanCode *HC, int n)
{
     int i, start, c, f;
     char *cd;
    
     (*HC) = (HuffmanCode )malloc((n + 1) * sizeof(char *));
     cd = (char *)malloc(n * sizeof(char));/*
编码的空间
*/
     cd[n - 1] = '/0';                     /*
编码结束符号
*/
    
     for(i = 1; i <= n; ++i)               /*
逐个叶子结点求编码
*/
     { 
         start = n - 1;                    /*
结束位置
*/
         for(c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
         {
             /*
从根到叶子求编码
*/             
             if(HT[f].lchild == c)
             {
                 cd[--start] = '0';
             }//if
             else
             {
                 cd[--start] = '1';
             }//else
         }//for
        
         /*
为第i个叶子结点求空间
*/
         (*HC)[i] = (char *)malloc((n - start) * sizeof(char));
         strcpy((*HC)[i], &cd[start]);     /*
cd复制到
HC*/
     }//for
}

/*打印编码*/   
void PrintHuffmanCode(HuffmanCode HC, unsigned int *w, int n)
{
     int i;
    
     printf("HuffmanCode
: /n");
     for(i = 1; i <= n; i++)
     {
         printf("%3d---", w[i - 1]);        /*
先打印权值
*/
         puts(HC[i]);                       /*
打印表
*/
         printf("/n");
     }
}
        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值