zoukankan      html  css  js  c++  java
  • 哈夫曼树的建立

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

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

    #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("
    %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] = '';
      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("
     %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;
          }
        }
      }
    }
  • 相关阅读:
    Exercise 1.1 Output a name and address
    常用vi编辑器命令行
    每天进步一点点:linux命令---mkdir,mv
    Tomcat的角色配置--Tomcat的后台管理
    centos下修改mysql root密码
    eclipse 比较实用的快捷键
    centos下/etc/sysconfig/下找不到iptables文件
    eclipse 常用设置(二) 优化相关的设置 提速和解决卡顿
    import javax.servlet 出错
    Java 文件下载
  • 原文地址:https://www.cnblogs.com/tqdlb/p/11962743.html
Copyright © 2011-2022 走看看