赫夫曼编码注释的讲解

大家知道电报吧,就是这种编码。是一种前缀编码。大家可以去数据结构的书中看详细的内容,已经很清楚了饿

因为涉及到结构体和数据结构,所以比较难读懂,我就不细讲了。

#include <stdio.h>

#include <string.h>
#include <stdlib.h>
#include <windows.h>
#define N 100
typedef struct hufmantnode{
    int weight;
    int left,right,parent;
}HUFNODE,*HUFTREE;
int select_two_min(HUFTREE HT,int n,int *min,int *min_second){ //从树的节点中选出两个最小的。并且partent是零
    int _min,_min_second;
    int i;
    int count=0;
    if(n<2) return -1;
    for(i = 1;i<=2*n-1;i++){
        if(count == 2)break;
        else if(count == 0){
            if(HT[i].parent == 0){_min = HT[i].weight;*min = i;count++;}
            else continue;
        }
        else if(count == 1){
            if(HT[i].parent == 0){
                if(HT[i].weight < _min){_min_second = _min;*min_second = *min;*min = i;_min = HT[i].weight;}
                else{_min_second = HT[i].weight;*min_second = i;count++;}
            }
            else continue;
        }
    }
    while(i<=2*n-1){
        if(HT[i].parent) {i++;continue;}
        else if(HT[i].weight <= _min&&HT[i].weight!='0'){       
            _min_second = _min;*min_second = *min;
            _min = HT[i].weight;*min = i;
        }
        else if(HT[i].weight <= _min_second&&HT[i].weight!='0'){
            _min_second = HT[i].weight;*min_second = i;
        }
        i++;
    }
    return 1;
   
}
int hufman(int *weight,int n,char ***HC,HUFTREE *tree)//这里用到了三级指针,因为想改变一个二级指针的地址,这里大家好好理解。有点绕,呵呵
{
    int i = 1;
    char **code;
    char* temp;
    HUFTREE HT = *tree;
    HT = (HUFTREE)malloc((2*n)*sizeof(HUFNODE));//对于赫夫曼树若有n个权重则会有2n-1个节点,这样我分配2n个节点,就把下标为0的节点舍去不用了。下面也有同样的例子。
    if(!HT){
        printf("no free mem\n");exit (-1);
    }
    while(i <=n )//对权重节点的初始化
        {/*HT[i] = {weight[i-1],0,0,0};i++;*/
            HT[i].weight=weight[i-1];
            HT[i].parent=0;
            HT[i].left=0;
            HT[i].right=0;
            i++;
        }
    while(i<=2*n-1)//对要生成的节点的初始化
        {/*HT[i] = {'0',0,0,0};i++;*/ //我原本这样赋值,但会有语法错,这样估计在c中是不允许的吧!
            HT[i].weight='0';
            HT[i].parent=0;
            HT[i].left=0;
            HT[i].right=0;
            i++;
        }
    for(i=n+1;i<=2*n-1;i++){  //第一个for实现树的建立
        int min,min_second;
        select_two_min(HT,n,&min,&min_second);
        HT[min].parent = i;
        HT[min_second].parent = i;
        HT[i].weight = HT[min].weight+HT[min_second].weight;
        HT[i].left = min;HT[i].right = min_second;
    }
    *HC= (char **)malloc(sizeof(char *)*(n+1));
    code = *HC;
    temp= (char*)malloc(sizeof(char)*(N+1));//临时存放编码结果
    if(!temp) {printf("no free mem \n");exit (-1);}
    for(i=1;i<=n;i++){
        int k=N;
        int p;int z;
        code[i] = (char *)malloc(N*sizeof(char));
        temp[k] = '\0';
        for(z=i,p = HT[z].parent;p != 0;z = p,p = HT[p].parent){
            if(HT[p].left == z)
                temp[--k] = '0';
            else
                temp[--k] = '1';   
        }
        strcpy(code[i],temp+k);//将编码存放到hunmancode【i】中。
    }
    return 1;
}
int
main(void)
{
    int weight[26];  //定义一个权重数组,存放26个英文字母
    int n = 26;
    char **hufmancode;//存放转换后的编码。是一个二级指针,每一个指针放一个字符串。
    HUFTREE HT; //定义赫夫曼树
    int i;
    char temp = 'a';
    for(i=0;i<n;i++)
        weight[i] = (int)(temp++); //初始化权重数组,赋值为26个字母
    putchar('\n');
    hufman(weight,n,&hufmancode,&HT);
    for (i = 1;i<=n;i++)//打印结果
        printf("%c\t\t%s\n",weight[i-1],hufmancode[i]);
    system("pause");
}
//select_two_min 这个函数希望大家好好看看,如果你会从一堆数中找到两个最小数,那么会很容易读懂,原理是一样的,不过我个人认为自己的算法(先找两个数做基准,再循环比较,进行更新)不是很高效,谁有好方法可以给我留言。呵呵