落絮飞雁

顺流而下,把梦做完

哈夫曼编码

已知某系统在通信联络中只可能出现8种字符,其概率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计哈夫曼编码。

综合训练:试编写一个将百分制分数转换为五级分制的程序。要求其时间性能尽可能好(即平均比较次数尽可能少)。假设学生成绩的分布情况如下:
分数 0-59 60-69 70-79 80-89 90-100
比例 0.05 0.15 0.40 0.30 0.10

#include
#include
#include
#define ERROR 0
#define OK 1
typedef int Status;
typedef struct {//声明哈夫曼树的结点
         int weight;
         int parent;
         int lchild;
         int rchild;
}Htnode,*Huffmantree;
typedef char ** Huffmancode;//相当于声明一个二维数组,来记录每个权值对应的编码。
void Select (Huffmantree &HT,int t,int &p,int &q);//选择结点中权值最小的两个结点,用p,q来返回。
void creathuffmantree(Huffmantree &HT,Huffmancode &HC,int *w,int n)//创建哈夫曼树。
{
         int m,i,p,q,j,start,s;
         if(n<=1)
          return;
         m=2*n-1;//当n大于1时,就需要2*n-1个结点
         HT=(Huffmantree)malloc(sizeof(Htnode)*(m+1));//因为0不存东西,而从1开始存,所以申请m+1个空间。
         for(i=1;i<=n;i++)//对叶子结点进行初始化,除权之外全赋值为0。
         {
                   HT[i].weight=w[i-1];
                   HT[i].parent=0;
                   HT[i].rchild=0;
                   HT[i].lchild=0;
         }
         for(i=n+1;i<=m;i++)//对非叶子结点进行初始化,所有的值全为0
         {
                   HT[i].weight=0;
                   HT[i].parent=0;
                   HT[i].rchild=0;
                   HT[i].lchild=0;
         }
         for(i=n+1;i<=m;i++)//这是创建树的主要步骤,找出权值和最小的两棵树,再把它们合并成一棵树,依次进行,知道走后还剩仅有的一棵树。
         {
                   Select(HT,i-1,p,q);//这是选择权值最小的两棵树的函数,并用p,q来返回,在上面已经声明过。
                   HT[i].weight=HT[p].weight+HT[q].weight;//对刚合并的新树的根结点的权值进行赋值。
                   HT[i].lchild=p;//新树的左孩子赋为p;
                   HT[i].rchild=q;//新树的右孩子赋为q;
             HT[p].parent=i;//把他们的双亲都赋为i;
                   HT[q].parent=i;
         }
         HC=(Huffmancode)malloc(sizeof(char*)*(n+1));//申请一个大小为n+1的存放指针的数组。
         char* cd=(char*)malloc(sizeof(char)*n);//申请一个一维数组,作为一个中转站,最后把他复制到HC中的一个数组中。

         for(i=1;i<=n;i++)//对哈夫曼树的数组从1到n进行依次遍历,这是从叶子结点到根节点。
         {
                   start=n-1;//对这个一位数组进行倒着存,最后正着读取。
              cd[start]='�';
                   s=i;
                   while(HT[s].parent!=0)
                   {
                            j=s;
                            s=HT[s].parent;
                            if(HT[s].lchild==j)//如果该结点是双亲结点的左孩子,应该把它赋为0;
                                     cd[--start]='0';
                            if(HT[s].rchild==j)//如果该结点是双亲结点的右孩子,应该把它赋为1;
                                     cd[--start]='1';
                   }
                   HC[i]=(char *)malloc(sizeof(char)*(n-start));
                   strcpy(HC[i],&cd[start]);//把cd数组里的内容复制到HC[i]里,再用cd去盛其他的编码。
         }
         free(cd);//最后可以把cd数组给释放了。
}
void Select (Huffmantree & HT,int t,int &min1,int &min2)//选择结点中权值最小的两个结点,用p,q来返回。
{
         int i=1,flag=0;
         while(flag<2)//这个while循环是为了找出前两棵树的根结点,把他们当成最小的两棵树,以后来做比较,求出最小的两个。
         {
           if(HT[i].parent!=0)//如果不是根结点,继续朝后找,直到找到根结点。
                     i++;
           else//如果是根结点,就把他们分别赋给min1和min2.
           {
                     if(flag==0)
             min1=i;
                     else
                              min2=i;
                    flag++;
                    i++;
           }
         }
         if(HT[min1].weight>HT[min2].weight)//对min1和min2进行比较,把最小的的付给min1,第二小的付给min2.
         {
                   t=min1;
                   min1=min2;
                   min2=t;
         }
    while(i<=t)//把以后的各个结点的权值与最小的两个比较,调整下,最后得出的就是最小的两个结点。
         {
                   if(HT[i].parent!=0)//如果不是根结点,继续朝后找,直到找到根结点。
                            i++;
                   else
                   {
                            if(HT[i].weight<=HT[min1].weight)//如果该结点的权值比最小的结点还小,把最小的两个全重新赋值。
                            {
                                     min2=min1;
                                     min1=i;
                            }
                            else if(HT[i].weight>=HT[min1].weight&&HT[i].weight<=HT[min2].weight)//如果该结点的权值在最小和第二小之间的话,
                                     //就把第二小的重新赋值。
                                     min2=i;
                            i++;
                   }
         }

}
Status exhuffmantree(Huffmantree &HT,int  m,char *code,int *ex,int &j)//这是解码的函数,m为那棵树的根结点,code是输入的哈夫曼码,
//解码后最后给他存到ex数组中,j为数组的长度。
{
         int i=0,k=m;
         while(code[i]!='�')//从根结点到叶子节点去匹配,输出最后的那个权值
         {
       if(code[i]=='0'&&HT[k].lchild!=0)//如果code[i]是0,并且左孩子不为0,则继续朝叶子结点找。
            {
                k=HT[k].lchild;
                      i++;
            }
            else if(code[i]=='1'&&HT[k].rchild!=0)//如果code[i]是1,并且右孩子不为0,则继续朝叶子结点找。
            {
                      k=HT[k].rchild;
                      i++;
            }
            else if(HT[k].rchild==0&&HT[k].lchild==0)//如果是叶子结点,则把它的权值赋给ex[j].
            {
                      ex[j]=HT[k].weight;
                j++;
                      k=m;
            }
            else//其他的则返回ERROR。
                      return ERROR;
         }
         if(HT[k].rchild==0&&HT[k].lchild==0)//当跳出循环的时候,说明应该到了叶子结点,如果是叶子结点,则把它的权值赋给ex[j].
         {
                   ex[j]=HT[k].weight;
             return OK;
         }
         else//其他的则返回ERROR。
                   return ERROR;
}
int main()
{
         Huffmantree HT;
         Huffmancode HC;
         char Code[100];
         int i, n,a[100],b[100],j=0,t;
         printf("输入叶子结点的个数n为:n");
         scanf("%d",&n);
         printf("依次输入n个叶子结点的权值为:n");
         for(i=0;i

原文标题:哈夫曼编码|落絮飞雁的个人网站
原文链接:https://www.luoxufeiyan.com/2014/11/16/%e5%93%88%e5%a4%ab%e6%9b%bc%e7%bc%96%e7%a0%81/
授权协议:创作共用 署名-非商业性使用 2.5 中国大陆
除注明外,本站文章均为原创;转载时请保留上述链接。