哈夫曼编码源程序

 

哈夫曼编码

一、源程序

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<conio.h>

/* Huffman 树的存储结构*/

#define n  8                 /*叶子数目根据需要设定*/

#define m  2*n-1  /* Huffman 树中结点总数 */

typedef struct

{int weight;                  /*结点的权值*/

int lchild,rchild,parent;   /*左、右孩子及双亲的下标*/

}htnode;

typedef htnode huffmantree[m+1];/* huffmantree是结构数组类型,其0号单元不用,存储哈夫曼树 */

 

typedef struct

{char ch;               /*存储字符*/

 char code[n+1];          /*存放编码位串*/

}codenode;

typedef codenode huffmancode[n+1];/*huffmancode是结构数组类型,其0号单元不用,存储哈夫曼编码*/

 

void inithuffmantree(huffmantree ht)           /*初始化哈夫曼树函数inithuffmantree()*/

{int i;

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

       {ht[i].weight=0;

              ht[i].lchild=ht[i].rchild=ht[i].parent=0;

       }

}

 

void inputweight(huffmantree ht)                /*输入权值函数 */

{int i;

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

              {printf("请输入第%d个权值:  ",i);

               scanf("%d",&ht[i].weight);

              }

       }

 

void selectmin(huffmantree  ht, int  i, int  *p1, int  *p2)

/* 在ht[1..i]中选两个权值最小的根结点,其序号为*p1和*p2,*p1中放权值最小的根结点的序号,*p2中放权值次小的根结点的序号*/

{int j,min1,min2;           /* min1,min2分别是最小权值和次小权值*/

       min1=min2=32767;

*p1=*p2=0;

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

              {if(ht[j].parent==0)                     /* j 为根结点*/

                     if(ht[j].weight<min1||min1==32767)

                            {

if(min1!=32767)     {min2=min1;  *p2=*p1;}

                             min1=ht[j].weight; 

*p1=j;

                            }

              else

                     if(ht[j].weight<min2||min2==32767)

                            {min2=ht[j].weight; 

*p2=j;}

              }

}

 

void createhuffmantree(huffmantree  ht)    /*构造huffman树,ht[m]为其根结点*/    

{                                

       int i,p1,p2;

       inithuffmantree(ht);              /* 将ht初始化*/

       inputweight(ht);                   /* 输入叶子权值至ht [1..n]的weight域*/

       for(i=n+1;i<=m;i++)             /* 共进行n-1次合并,新结点依次存于ht[i]中*/

              {selectmin(ht,i-1,&p1,&p2); /*在ht [1.. i-1]中选择两个权值最小的根结点,其序号分别为p1和p2*/

               ht[p1].parent=ht[p2].parent=i;

               ht[i].lchild=p1;            /* 最小权值的根结点是新结点的左孩子*/

               ht[i].rchild=p2;    /* 次小权值的根结点是新结点的右孩子*/

               ht[i].weight=ht[p1].weight+ht[p2].weight;

              }

}

 

void huffmancodes(huffmantree ht,huffmancode  hcd) /*根据huffman树ht求huffman编码*/

{

int c,p,i;                              /* c和p分别指示 ht中孩子和双亲的位置 */

char cd[n+1];                      /* 临时存放编码*/

int start;                       /* 指示编码在cd 中的起始位置*/

cd[n]='\0';     

getchar();                     /* 编码结束符*/

printf("请输入字符");

        for(i=1;i<=n;i++)         /* 依次求叶子ht [i]的编码*/

         {  hcd[i].ch=getchar();      /* 读入叶子ht [i]对应的字符*/

               start=n;                      /* 编码起始位置的初值*/

               c=i;                                   /* 从叶子ht [i]开始上溯*/

              while((p=ht[c].parent)!=0)           /* 直至上溯到ht [ c]是树根为止*/

          { cd[--start]=(ht[p].lchild==c)?'0':'1';  /*若ht [ c]是ht[p]的左孩子,则生成代码0,否则生成代码1*/

               c=p;                    /* 继续上溯*/

              }

              strcpy(hcd[i].code,&cd[start]);           /* 复制编码位串*/

       }

printf("\n");

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

printf("第%d个字符%c的编码为%s\n",i,hcd[i].ch,hcd[i].code);

}

 

void main()

{huffmantree t;

       huffmancode h;

printf("\n请输入%d个权值\n",n);

createhuffmantree(t);                          /* 构造huffman树*/

huffmancodes(t,h);                      /* 构造huffman编码*/

}

运行结果

心得

getch与getchar基本功能相同,差别是getch直接从键盘获取键值,不等待用户按回车,只要用户按一个键,getch就立刻返回, getch返回值是用户输入的ASCII码,出错返回-1.输入的字符不会回显在屏幕上.

getch函数常用于程序调试中,在调试时,在关键位置显示有关的结果以待查看,然后用getch函数暂停程序运行,当按任意键后程序继续运行.

#include<iostream>

using namespace std;

 

struct htnode     //哈夫曼树结点结构定义

{

 char ch;         //结点值

 int weight;      //结点权值

 int parent;      //父结点下标

 int lchild,rchild;   //左、右孩子结点下标

};

 

class huffmantree    //哈夫曼树类定义

{

public:

 void code(char str1[],int w[],int n);  //编码

 void uncode(char str1[],char str2[],int n);  //解码

private:

    htnode ht[3000];    //用数组存储哈夫曼树

    void creathuffmantree(char str1[],int w[],int n);  // 创建哈夫曼树

    void select(int pos,int &r1,int &r2);

};

//在数组ht中从0到pos位置,查找未加入哈夫曼树的权值最小的两个数的位置r1,r2

//r1为权值最小的位置,r2为权值第二小的位置

void huffmantree::select(int pos,int &r1,int &r2)

{

    r1=r2=0; //初始化为0位置

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

    {

        if(ht[i].parent!=0)    //父结点不等于0,表示已加入哈夫曼树

            continue;          //继续向前查找

        if(r1==0)              //把r1设置为1

            r1=i;

        else if(r2==0)         //把r2设置为2

            r2=i;

 //从i等于3开始比较。我认为这里程序有问题,无法得到权最小的两位置,你自己再改改

        else if(ht[i].weight<ht[r1].weight) //如小于r1的权则设置r1为i

            r1=i;

        else if(ht[i].weight<ht[r2].weight) //如大于r1的权,再和r2的权比较

            r2=i;

    }

}

// 创建哈夫曼树,str1[]为结点值数组,w[]为权值数组,共n个结点

void huffmantree::creathuffmantree(char str1[],int w[],int n)

{

 int pos;

 //把结点值和权值复制到数组ht

 for(pos=1;pos<=n;pos++)    //注意没有使用ht数组位置为0的空间

 {

  ht[pos].weight=w[pos-1];  //结点权值

  ht[pos].ch=str1[pos-1];   //结点值

  ht[pos].parent=ht[pos].lchild=ht[pos].rchild=0;  //父结点为0表示未加入哈夫曼树,左右孩子都为0表示叶子结点

 }

//这是构造哈夫曼树的过程,即设置数组ht的其他结点

 for(pos=n+1;pos<=2*n-1;pos++)   //注意用n个数值构造的哈夫曼树有2*n-1个结点

 {

  int r1,r2;

  select(pos-1,r1,r2);

  ht[r1].parent=ht[r2].parent=pos;  //把r1,r2结点加入哈夫曼树,并设置他们的父结点位置为pos

  ht[pos].lchild=r1;      //设置pos结点的左孩子为r1

  ht[pos].rchild=r2;   //设置pos结点的右孩子为r2

  ht[pos].weight=ht[r1].weight+ht[r2].weight;  //设置pos结点的权值为左右孩子权值的和

  ht[pos].parent=0;       //其父结点为0

 }

}

//求哈夫曼编码

void huffmantree::code(char str1[],int w[],int n)

{

 creathuffmantree(str1,w,n); //建立哈夫曼树

 int start,c,i,f,j;

 char *cd;

 cd=new char[n]; //用于保存哈夫曼编码

 cd[n-1]='\0';   //设置字符串结束符

 for(i=1;i<=n;i++)  //分别输出n个结点的哈夫曼编码

 {

  start=n-1;     //注意从cd数组的末尾向前加入编码

  for(c=i,f=ht[i].parent;f!=0;c=f,f=ht[c].parent) //从叶子结点往上走到根结点为止

  {

   //左0,右1

   if(ht[f].lchild==c) 

    cd[--start]='0';

   else

    cd[--start]='1';

  }

  cout<<"结点"<<str1[i-1]<<"的编码为:"<<endl;

  for(j=start;j<n;j++)  //输出所有叶子结点

  cout<<cd[j];

  cout<<endl;

 }

 delete []cd;    //撤销

}

//翻译哈夫曼编码,str1[]为结点值,str2[]为哈夫曼编码,共n个结点

//输出哈夫曼编码为str2的结点值

void huffmantree::uncode(char str1[],char str2[],int n)

{

 int i,f;

 char c;

 for(i=0;i<strlen(str2);)  //从根结点往下走到叶子结点

 {

  //根结点在数组ht最后一个位置

  //从上往下也是左0右1

  for(f=2*n-1;ht[f].lchild!=0&&ht[f].rchild!=0;)

  {

   c=str2[i];

   if(c=='1')  //等于1往右走

   {

    f=ht[f].rchild;

    i++;

   }

   else       //等于0往左走

   {

    f=ht[f].lchild;

    i++;

   }

  }

  cout<<ht[f].ch;  //输出找到的叶子结点

 }

 cout<<endl;

}

 

//这个不用注释了吧

int main()

{

 char str[27],str2[3000],c;

 char ch[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};

 int cd[27],s,len,i,w[27];

sb1:

    cout<<"请输入要编码的字符串"<<endl;

 cin>>str;

 huffmantree obj;

 s=0;

 memset(cd,0,sizeof(cd));

 len=strlen(str);

 for(i=0;i<len;i++)

 {

  cd[str[i]-'a']++;

 }

 for(i=0;i<26;i++)

 {

  if(cd[i])

  {

   str[s]=ch[i];

   w[s]=cd[i];

   s++;

  }

 }

 cout<<"各节点编码如下:"<<endl;

 obj.code(str,w,s);

sb2:

 cout<<"请输入要解码的01串"<<endl;

 cin>>str2;

 cout<<"解码结果如下:"<<endl;

 obj.uncode(str,str2,s);

 cout<<"是否继续解码?(Y/N)"<<endl;

 getchar();

 c=getchar();

 if(c=='Y')

  goto sb2;

 cout<<"是否继续编码?(Y/N)"<<endl;

 getchar();

 c=getchar();

 if(c=='Y')

  goto sb1;

 return 0;

}

你可能感兴趣的:(c,struct,delete,存储,Class)