哈夫曼树的建立

哈夫曼树,又叫赫夫曼树什么其他的了,这个东西吧,主要用来对一组数据的出现概率来进行建数,这样可以使得概率大的放在前面,就使得调用简单一些,而概率小的就放到后面,其实就是对数据的一个优化处理了。

接下来我们就来看看怎么建树吧:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>                        /为什么会多这么一个string呢,这是因为后面会用到一个strcpy(复制)函数

typedef struct{
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree;                     /哈夫曼树的结构体定义,权重,父节点,左右孩子结点

typedef char **HuffmanCode;               /这个是我们的哈夫曼编码的格式转换

一:建树

 

 

通过上表可知,首先我们对数据编号,并令其 parent ,lchild 和 rchild 初始化为 0,接下来我们通过每次选出最小的两个数据然后对其父节点进行编号,并对新生成的父节点的相关信息进行编辑,也就是它的权重,左右孩子结点,接下来继续找最小的就好了,遍历完了之后就能得到右边的这个表了,接下来就是哈夫曼编码了

 

看下图

 我们可以知道左边排0,右边排0,再想到我们上面的排序方式,可以知道我们需要从后面往前面进行逆向的编码,所以我们可以定义一个字符数组(也就是前面做了类型转换的),然后从尾部开始往前面赋值。

接下来就让我们看看详细的代码吧(有点小长哦):

void HuffmanCoding(HuffmanTree HT,HuffmanCode *HC,int *w,int n){              /第一个定义的就是我们哈夫曼树,第二个是字符数组,第三个就是我们的权重数组了
  HuffmanTree p;   
  int i,m,s1,s2,start,c,f;
  char *cd;                                                                  /定义一个字符数组来进行单个数据的编码存储
  if(n<=1) return;
  m = 2 * n -1;                                                              /m就是我们总的数据个数,包括非叶子结点
  HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));
  p = HT;                                                                    /这里注意,要先分配空间,再进行传值,不然 p 是没有空间的
  for(i = 0;i<n;i++){                                                        /我这里写了初始的赋值函数,也可以直接在主函数里面定义
    printf("请输入第 %d 个权值: ",i+1);
    scanf("%d",&w[i]);
  }
  for(i = 1;i<=n;++i,++w){                                                   /这里就是把我们的初始数据进行编号
    p[i].weight = *w;                                                       /因为前面我们定义的 w 是 *w 所以直接用++w就可以指向下一个数据了
    p[i].parent=p[i].lchild=p[i].rchild = 0;
  }
  for( ;i<=m;++i)                                                            /然后再对后面的位置先初始化
    p[i].weight=p[i].parent=p[i].lchild=p[i].rchild = 0;
  for(i = n+1;i<=m;++i){                                                     /这里就开始循环找最小值了
    Select(HT,i-1,&s1,&s2);                                                 /select函数用于找两个最小值,在后面哦
    HT[s1].parent = i;
    HT[s2].parent = i;
    HT[i].lchild = s1;
    HT[i].rchild = s2;
    HT[i].weight = HT[s1].weight + HT[s2].weight;
  }
  printf(" weight parent lchild rchild");
  for(i = 1;i<=m;i++)
    printf("\n%8d %8d %8d %8d",HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
  *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';
      else cd[--start] = '1';
    (*HC)[i] = (char*)malloc((n-start)*sizeof(char));
    strcpy((*HC)[i],&cd[start]);
   }

  for(i = 1;i<=n;i++){
    printf("\n %4d 的哈夫曼编码为: %s ",HT[i].weight,(*HC)[i]);
  }
  free(cd);
}

二:select函数

通过上面我们知道你要写一个select函数,用来找到没有父节点的所有数据中的最小的两个,注意是没有父节点的,没有父节点代表什么,代表它还没有被找到过,因为找到过的的父节点都会被标号。

void Select(HuffmanTree HT, int k, int *s1, int *s2)
{
  int a, b,i;
  *s1 = *s2 = 0;
  a = b = MAXVALUE;
  for (i = 0; i <= k; i++)
  {
    if (HT[i].parent == 0)
    {
      if (HT[i].weight < a)
      {
        b = a;
        a = HT[i].weight;
        *s2 = *s1;
        *s1 = i;
      }
      else if (HT[i].weight < b)
      {
        b = HT[i].weight;
        *s2 = i;
      }
    }
  }
}

 

posted @ 2019-11-30 15:49  随...风  阅读(1154)  评论(0编辑  收藏  举报