现在的位置: 首页 > 综合 > 正文

huffman算法的编码,主体人家的。。但也算认真的自己写的

2013年10月13日 ⁄ 综合 ⁄ 共 5006字 ⁄ 字号 评论关闭
#include "iostream"
#include "iomanip"  //setw()
#include "fstream"  //输入输出文件
#include "stdlib.h"  //system(del)功能
using namespace std;
int m,s1,s2,rem=0; //定义全局变量,其中rem为计步器,记录编码的步骤数
typedef struct { 
unsigned int weight; //以无符号整形定义权值
unsigned int parent,lchild,rchild; //定义节点,左子树,右子树
}HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树 
typedef char *HuffmanCode; //动态分配数组存储哈夫曼编码表
typedef struct { 
 int pr;//是否显示过程的控制
 int r;//左子树与右子树的关系
}FR;
void firstrun(int *p1,int *p2)    //首次运行时进行程序设置,主要为建树时左右子树关系及编码过程是否输出
{ int px[2];
  ifstream infile("first.dat");  //以输入方式调用文件first.dat,如果调用不成功,则要求用户初始化程序
  if(! infile)
  {cout<<setw(40)<<"欢迎使用本程序,首次使用才会看到此提示"<<endl;
  cout<<setw(20)<<"程序初始化开始"<<endl;
  cout<<"请选择是否在建赫夫曼编码时显示过程:1为显示,0为不显示:";
  cin>>*p1;
  cout<<"请选择左子树与右子树的关系:1为左子树>右子树,0为左子树<右子树/n习惯性为0及左子树<右子树:";
  cin>>*p2;
  ofstream outfile("first.dat");
  if(! outfile)
  {cerr<<"输出错误!"<<endl;//为防止出现输出错误,以在重置功能中先删除了first.dat
  exit(1);
  }
  px[0]=*p1;px[1]=*p2;
  for(int i=0;i<2;i++)
  {outfile<<px[i]<<" ";} 
  outfile.close ();}
  for (int i=0;i<2;i++)
  {infile>>px[i];}
  *p1=px[0];*p2=px[1];//读取成功或者初始化成功后返回控制数据pr和r
  infile.close();
}
void Select(HuffmanTree HT,int n,int r) { //选择函数,用于选择最小的两个数
int i,j; 
for(i = 1;i <= n;i++) 
if(!HT[i].parent){s1 = i;break;} 
for(j = i+1;j <= n;j++) 
if(!HT[j].parent){s2 = j;break;} 
for(i = 1;i <= n;i++) 
if((HT[s1].weight>HT[i].weight)&&(!HT[i].parent)&&(s2!=i))s1=i; 
for(j = 1;j <= n;j++) 
if((HT[s2].weight>HT[j].weight)&&(!HT[j].parent)&&(s1!=j))s2=j;
if(r==0)      //控制器,控制建树时左子树与右子树的关系
{
   if(s1>s2) 
   { int temp;
     temp=s1; 
     s1=s2; 
     s2=temp;
} 
}
if(r==1)
{
   if(s2>s1) 
   { int temp;
     temp=s1; 
     s1=s2; 
     s2=temp;
} 
}
}

void printprocess(HuffmanTree HT,int m,int pr){
rem=rem+1;//计步器
if(pr==1){//控制器,只有pr=1时才执行以下代码段
cout<<endl;
cout<<"哈夫曼树的构造过程如下所示:";
if (rem==1) cout<<"HT:处态"<<endl;
else cout<<"HT:"<<rem<<"态"<<endl;//显示此时是第几步变化
cout<<"  结点    权值     根   左子树   右子树";
cout<<endl; 
for (int i=1; i<=m; i++) 
{
cout<<setw(4)<<i<<setw(8)<<HT[i].weight<<setw(8)<<HT[i].parent<<setw(8)<<HT[i].lchild<<setw(8)<<HT[i].rchild<<endl; 
if(HT[i+1].weight==0) break;
}//for(int i=1; i<=m; i++){} 结尾
if(rem>1){cout<<endl;
cout<<"选择的左子树为:"<<s1<<"选择的右子树为:"<<s2<<endl; }
 cout<<" 按任意键,继续 ..."; 
 getchar();
}//if(pr==1){} 结尾
}
void HuffmanCoding(HuffmanTree &HT, HuffmanCode HC[], int *w, int n,int r,int pr) { 
// w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的赫夫曼编码hc
int i; 
char *cd; 
int p; 
int cdlen;
if (n<=1) {cout<<"输入的数值错误!"<<endl;return;} 
m = 2 * n - 1; 
HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode)); // 0号单元未用 
for (i=1; i<=n; i++) { //初始化 *p={*w,0,0,0}赋值方式错误
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; 
} 
printprocess(HT,m,pr); //调用显示进程的功能,如pr=0及不显示,则只记步
for (i=n+1; i<=m; i++) { // 建哈夫曼树 
// 在HT[1..i-1]中选择parent为0且weight最小的两个结点, 
// 其序号分别为s1和s2。 
Select(HT, i-1,r); 
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; 
printprocess(HT,m,pr);
}
//------无栈非递归遍历哈夫曼树,求哈夫曼编码 
cd = (char *)malloc(n*sizeof(char)); // 分配求编码的工作空间 
p = m; cdlen = 0; 
for (i=1; i<=m; ++i) // 遍历哈夫曼树时用作结点状态标志 
HT[i].weight = 0; 
while (p) { 
if (HT[p].weight==0) { // 向左 
HT[p].weight = 1; 
if (HT[p].lchild != 0) { p = HT[p].lchild; cd[cdlen++] ='0'; } 
else if (HT[p].rchild == 0) { // 登记叶子结点的字符的编码 
HC[p] = (char *)malloc((cdlen+1) * sizeof(char)); 
cd[cdlen] ='/0'; strcpy(HC[p], cd); // 复制编码(串) 
} 
} else if (HT[p].weight==1) { // 向右 
HT[p].weight = 2; 
if (HT[p].rchild != 0) { p = HT[p].rchild; cd[cdlen++] ='1'; } 
} else { // HT[p].weight==2,退回退到父结点,编码长度减1 
HT[p].weight = 0; p = HT[p].parent; --cdlen; 
} 
} 
} // HuffmanCoding
void input(int *n,int **w){//全部使用指针来进行值传递,w为指向指针的指针
cout<<"输入结点数:"; 
cin>>*n; 
//HC = (HuffmanCode *)malloc(n*sizeof(HuffmanCode)); //在这里开辟空间来存储hc同样可行,只需将hc的头位置传回menu()函数
*w = (int *)malloc((*n)*sizeof(int)); //为指针w开空间
cout<<"输入"<<*n<<"个结点的权值"<<endl; 
int i;
for(i=0;i < *n;i++) 
cin>>(*w)[i];//此处需考虑优先顺序,*w[i]是错误的
 
}
void Print(HuffmanCode HC[],int n,int *w)//输出结果
{
cout<<"/n得到此编码共进行了"<<rem<<"步"<<endl;
cout<<"/n各结点的哈夫曼编码:"<<endl; 
for(int i = 1;i <= n;i++) 
cout<<setw(2)<<i<<"<"<<setw(4)<<w[i-1]<<">"<<HC[i]<<endl; 
getchar();
}
void writefiled(HuffmanCode HC[],int n,int *w)//输出文件
{  
 ofstream outfile("HT.txt");
 if(! outfile)
 {cerr<<"输出错误!"<<endl;
 exit(1);
 }
 for(int i = 1;i <= n;i++) 
 {outfile<<setw(2)<<i<<"<"<<setw(4)<<w[i-1]<<">"<<HC[i]<<endl;} 
 outfile<<'/0';
 outfile.close ();
}
void pmenu()//打印菜单
{
cout<<setw(25)<<"功能菜单如下:"<<endl;
  cout<<"* * * * * * * * * * * * * * * * * * * * * * * * *"<<endl;
  cout<<"*    1:输入数据                                 *"<<endl;
  cout<<"*    2:编码(需输入数据)                         *"<<endl;
  cout<<"*    3:显示编码(需编码)                         *"<<endl;  
  cout<<"*    4:输出编码文件(将编码输出为txt文件)        *"<<endl;
  cout<<"*    5:重置程序                                 *"<<endl;
  cout<<"*    0:退出                                     *"<<endl;
  cout<<"* * * * * * * * * * * * * * * * * * * * * * * * *"<<endl;
  cout<<"请输入功能字符:";
}
void menu()              //菜单
{   FR first;
 int pr=first.pr=0;
 int r=first.r=0;
 firstrun(&pr,&r);
    HuffmanTree HT;HuffmanCode *HC;int *w,n;
    pmenu();
 
 while(1)
 {
  char ch;
  cin>>ch;
 switch (ch)  
   {
 case '1':{input(&n,&w);
       HC = (HuffmanCode *)malloc(n*sizeof(HuffmanCode));
    pmenu();
    continue;}
   case '2':HuffmanCoding(HT,HC,w,n,r,pr);::rem=0;pmenu();continue;
    //重复调用第二功能会是计步器重复记步,这里用全局变量运算符(::rem=0)进行计步器清零
   case '3':Print(HC,n,w);cout<<"按任意键继续!"<<endl;getchar();pmenu();continue;
   case '4':system("del HT.txt");writefiled(HC,n,w);cout<<"输出成功,按任意键继续!"<<endl;getchar();pmenu();break;
    //此处删除HT.txt以防止出现报错
   case '5':system("del first.dat");menu();break;//此处删除first.dat以防止出现报错
   case '0':cout<<"y(继续) or n(退出)"<<endl;
   char e;cin>>e;if (e=='y') {pmenu();break;}else exit(1);;
   default:cout<<"你输入错误!"<<endl;   
  }
 }
}
void main()
{  
menu();
}

 

运行起来还是可以的。。基本完成了我想的结果。

抱歉!评论已关闭.