huffman树的生成与编码的实现

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int UINT;
typedef char  ElemType;
typedef struct{
 ElemType elem;
 UINT weight;
 UINT parent,lchild,rchild;
}HTNode, *HuffmanTree;
typedef char** HuffmanCode;
#define N 40
UINT Weight[N]; //用于记录以出现过的权值的下标
int wi = 0;
void HuffmanCoding(HuffmanTree&, HuffmanCode&, int *w, char *e,int n);
void Select(HuffmanTree, int, int&, int&);
void OutHuffmanInfo(HuffmanTree hTree, HuffmanCode hCode,int n);
int main()
{
 printf("Text huffmanTree and huffmancode!/n");
 HuffmanTree hTree = NULL;
 HuffmanCode hCode = NULL;
 char elem[]={"abcdefgh"};
 int weight[]={5,29,7,8,14,23,3,11};
 int n = 8;
 HuffmanCoding( hTree, hCode,  weight, elem, n);
 
 OutHuffmanInfo(hTree,hCode,n);
 system("PAUSE");
 return 0;
}

void HuffmanCoding(HuffmanTree& hTree, HuffmanCode& hCode, int *w, char *e,int n)
{
 if( n<=1) return;
 int m = 2*n-1;
 hTree = (HuffmanTree)malloc((m+1)*sizeof(HTNode));
 HuffmanTree pTree = hTree+1;
 
 int ix;
 for(ix=1; ix<=n; ++ix,++pTree,++w,++e)
 {
  pTree->elem   = *e;
  pTree->weight = *w;
  pTree->lchild = 0;
  pTree->rchild = 0;
  pTree->parent = 0;  
 }
 for(; ix <=m; ++ix,++pTree)
 {
  pTree->elem   = '/0';
  pTree->lchild = 0;
  pTree->parent = 0;
  pTree->rchild = 0;
  pTree->weight = 0;
 }
 for( ix=n+1; ix<=m; ++ix)
 {
  int s1=-1,s2=-1;
  Select(hTree,ix-1,s1,s2);
  //加判断主要为了防止到尾部时产生非法数据
  if(s1!=-1) hTree[s1].parent = ix;
  if(s2!=-1) hTree[s2].parent = ix;
  if(s1!=-1) hTree[ix].lchild = s2; //这两个的指向顺序没有关系,可以让lchild = s1,rchild = s2
  if(s2!=-1) hTree[ix].rchild = s1; //只不过产生不同的编码.
  if(s1!=-1 && s2!=-1) hTree[ix].weight = hTree[s1].weight+hTree[s2].weight;
  else if(s1!=-1) hTree[ix].weight = hTree[s1].weight;
    else  hTree[ix].weight = hTree[s2].weight;
 }

 //-------------从叶子到根逆向求编码--------------
 hCode = (HuffmanCode)malloc((n+1)*sizeof(char*));
 char *cd    = (char*)malloc(n*sizeof(char)); //记录编码表 
 cd[n-1] = '/0';
 
 for(ix=1; ix<=n; ++ix)
 {
  int start = n-1; 
  int cur  = -1;  //记录当前位置
  int fpos = -1;  //记录父结点位置
  //这个for就是从叶子向根结点走,通过父结点的左或右孩子是否等于当前结点来得到编码
  for( cur=ix, fpos=hTree[ix].parent; fpos!=0; cur=fpos,fpos=hTree[fpos].parent)
  {
   if(hTree[fpos].lchild == cur) cd[--start] = '0';
   else cd[--start] = '1';
  }
  hCode[ix] = (char*)malloc((n-start)*sizeof(char));
  strcpy(hCode[ix],&cd[start]);
 }
 free(cd);
}
//寻找树中权值最小的点.找到后把该位置记录下来,下次查找跳过该点
void Select(HuffmanTree hTree, int imax, int& s1, int& s2)
{
 UINT temp1 = 10000;
 UINT temp2 = 10000;
 int  pos = -1;
 bool flag = true;
 for(int ix = 1; ix<=imax; ++ix)
 { //第一次进来wi为空,进if产生第一个权值最小的pos
  if(wi == 0)
  {
   if(temp1>hTree[ix].weight)
   { 
    temp1 = hTree[ix].weight;
    pos = ix; 
   }
  }
  else
  { //排除已取过值的下标
   for(int jx = 0; jx < wi; jx++)
   {
    if(ix != Weight[jx]) flag = true;
    else
    {
     flag = false;
     break;
    }
   }
   if(flag)
   {
    for(int jx = 0; jx<wi; ++jx)
    {
     if(temp1>hTree[ix].weight)
     {
      temp1 = hTree[ix].weight;
      pos = ix;
     }
    }
   }   
  }//else
 }
 Weight[wi++] = s1 = pos; 
  
 for(int ix = 1; ix<=imax; ++ix)
 {
  for(int jx = 0; jx < wi; jx++)
  {
   if(ix != Weight[jx]) flag = true;
   else
   {
    flag = false;
    break;
   }
  }
  if(flag)
  {
   for(int jx = 0; jx<wi; ++jx)
   {
    if(temp2>hTree[ix].weight)
    {
     temp2 = hTree[ix].weight;
     pos = ix;
    }
   }
  }   
 }
 Weight[wi++] = s2 = pos;
}
void OutHuffmanInfo(HuffmanTree hTree, HuffmanCode hCode,int n)
{
 HuffmanTree outTree = hTree;
 HuffmanCode outCode = hCode;
 
 for(int ix = 1; ix<=n; ++ix)
 {
  printf("/n");
  printf("第%d个字符: %c/t拥有权值为%d/t产生的编码是: %s/n",ix,outTree[ix].elem,outTree[ix].weight,outCode[ix]);
  //printf("产生的编码是: %s/n",outCode[ix]);
  printf("/n");
 }
}
/*
//对hTree的生成顺序的跟踪结果
hTree 0x000332d8 HTNode * &
hCode 0x00000000 char * * &
hTree[15] {weight=100 parent=0 lchild=13 ...} HTNode
hTree[14] {weight=58 parent=15 lchild=2 ...} HTNode
hTree[13] {weight=42 parent=15 lchild=11 ...} HTNode
hTree[12] {weight=29 parent=14 lchild=5 ...} HTNode
hTree[11] {weight=19 parent=13 lchild=9 ...} HTNode
hTree[10] {weight=15 parent=12 lchild=3 ...} HTNode
hTree[9] {weight=8 parent=11 lchild=7 ...} HTNode
hTree[8] {weight=11 parent=11 lchild=0 ...} HTNode
hTree[7] {weight=3 parent=9 lchild=0 ...} HTNode
hTree[6] {weight=23 parent=13 lchild=0 ...} HTNode
hTree[5] {weight=14 parent=12 lchild=0 ...} HTNode
hTree[4] {weight=8 parent=10 lchild=0 ...} HTNode
hTree[3] {weight=7 parent=10 lchild=0 ...} HTNode
hTree[2] {weight=29 parent=14 lchild=0 ...} HTNode
hTree[1] {weight=5 parent=9 lchild=0 ...} HTNode
hTree[0] {weight=3452816845 parent=3452816845 lchild=3452816845 ...} HTNode
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值