• Huffman编码


    #include<iostream>

    #include<conio.h>

    #include <iomanip>

    #include<stdlib.h>

    using namespace std;

    typedef struct{

    unsigned int weight;

    unsigned int parent,lchild,rchild;

    }HTNode,*HuffmanTree;

    typedef char*HuffmanCode;

    typedef struct{

    int num;

    int value;

    }myHuff;

    int HuffDepth(HuffmanTree HT,int i)//返回树深度

    {

    int dep=0;

    while(1)

    {

    if(HT[i].lchild ==0)

    {

    break;

    }

    else

    {

    dep++;

    i=HT[i].lchild;

    }

    }

    return dep;

    }

    //动态选取哈夫曼二叉树节点最小两个值

    void Select(const HuffmanTree HT, int n, int &s1,int &s2)

    {

    myHuff *a=new myHuff[n+1]; //定义结构体数组拷贝哈夫曼数组中的数据进行排序取值,主要目的是保护原来的哈夫曼数据

    myHuff temp;//交换数据时的空容器

    int k,i,j;

    for(i=1;i<n+1;i++)//拷贝哈夫曼数据

    {

    a[i].value=HT[i].weight;

    a[i].num=i;

    }

    for(i=1;i<n;i++)//对数据进行选择排序

    {

    k=i;

    for(j=i+1;j<n+1;j++)

    {

    if(a[j].value >a[k].value )

    {

    k=j;

    }

    }

    if(k!=i)

    {

    temp=a[k];

    a[k]=a[i];

    a[i]=temp;

    }

    }

    for(i=1;i<n+1;i++)//此处是为了保持数据排序的一致性,保持新数据在后,老数据在前

    {

    if(a[i].value==a[i+1].value&&HuffDepth(HT,a[i].num)==0)

    {

    temp=a[i+1];

    a[i+1]=a[i];

    a[i]=temp;

    }

    }

    int p=n;//下面为取最小两数据的具体算法,有点复杂

    while(1)

    {

    if(HT[a[p].num].parent ==0)

    {

    s1=a[p].num;

    p--;

    break;

    }

    p--;

    }

    while(1)

    {

    //选取没有父节点,且a的下标要大于1的p(否则会数据溢出) 

    if(p!=1&&HT[a[p].num].weight ==HT[a[p-1].num].weight&&HT[a[p].num].parent ==0&&HT[a[p-1].num].parent ==0)

    {

    if(HT[a[p].num].parent ==0&&HuffDepth(HT,a[p].num)==0)//在数值相同的情况下比较节点深度

    {

    s2=a[p].num;

    p--;

    break;

    }

    else

    {

    p--;

    }

    }

    if(HT[a[p].num].parent ==0)

    {

    s2=a[p].num;

    p--;

    break;

    }

    p--;

    }

    delete []a;

    }

    void HuffmanCoding(HuffmanTree &HT, HuffmanCode *HC, int *w, int n) {

      // 算法6.12

      // w存放n个字符的权值(均>0),构造哈夫曼树HT,

      // 并求出n个字符的哈夫曼编码HC

      int i, j, m, s1=0, s2=0, start;

      char *cd;

      unsigned int c, f;

      if (n<=1) return;

      m = 2 * n - 1;

      HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));  // 0号单元未用

      for (i=1; i<=n; i++) { //初始化

        HT[i].weight=w[i-1];

        HT[i].parent=0;

        HT[i].lchild=0;

        HT[i].rchild=0;

      }

      for (i=n+1; i<=m; i++) { //初始化

        HT[i].weight=0;

        HT[i].parent=0;

        HT[i].lchild=0;

        HT[i].rchild=0;

      }

      printf("\n哈夫曼树的构造过程如下所示:\n");

      printf("HT初态:\n  结点  weight  parent  lchild  rchild");

      for (i=1; i<=m; i++)

        printf("\n%4d%8d%8d%8d%8d",i,HT[i].weight,

                HT[i].parent,HT[i].lchild, HT[i].rchild);

        printf("    按任意键,继续 ...");

      getch();

      for (i=n+1; i<=m; i++) {  // 建哈夫曼树

        // 在HT[1..i-1]中选择parent为0且weight最小的两个结点,

        // 其序号分别为s1和s2。

        Select(HT, i-1, s1, s2);

        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("\nselect: s1=%d   s2=%d\n", s1, s2);

        printf("  结点  weight  parent  lchild  rchild");

        for (j=1; j<=i; j++)

          printf("\n%4d%8d%8d%8d%8d",j,HT[j].weight,

                 HT[j].parent,HT[j].lchild, HT[j].rchild);

        printf("    按任意键,继续 ...");

        getch();

      }

      //--- 从叶子到根逆向求每个字符的哈夫曼编码 ---

      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)); 

             // 为第i个字符编码分配空间

        strcpy(HC[i], &cd[start]);    // 从cd复制编码(串)到HC

      }

      free(cd);   // 释放工作空间

    } // HuffmanCoding

    int main()

    {

    int a[8]={5,29,7,8,14,23,3,11};

    HuffmanTree HT;

    HuffmanCode *HC=new HuffmanCode[9];

    HuffmanCoding(HT,HC,a,8);

    cout<<endl<<"得到的哈夫曼编码如下:"<<endl;

    for(int i=1;i<=8;i++)

    {

    cout<<setw(8)<<HT[i].weight<<setw(8)<<HC[i]<<endl;

    }

    delete []HC;

    printf("    按任意键,继续 ...");

        getch();

    return 0;

    }

  • 相关阅读:
    【Canvas】摆线模拟
    【JS】JS正则表达式常见用法(验证、查找和替换)
    【Canvas】将屏幕坐标系转换成笛卡尔坐标系
    【Canvas】狗撵兔子和贝塞尔曲线
    精妙的SQL和SQL SERVER 与ACCESS、EXCEL的数据导入导出转换
    用Javascript实现HtmlEncode与HtmlDecode的另类方法
    [Javascript] 如何在客户端验证表单被改变
    关于IE6和IE7关闭窗口时提示和不提示以及上传图片前的本地预览解决办法
    项目开发经验谈(一)
    Windows 7 开发新特性
  • 原文地址:https://www.cnblogs.com/pengJk/p/4972998.html
Copyright © 2020-2023  润新知