哈夫曼编码

来源:互联网 发布:centos下安装图形界面 编辑:程序博客网 时间:2024/05/17 10:27

几天看了下哈夫曼树, 输出费了点功夫 贴代码 留被参考

 /*
 实现对26个字符的编码
*/
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
//haffman tree 节点数据结构
typedef struct Node {
 //预编码的字符
 char value;
          //父节点
 struct Node * parent;
 struct Node * left;
 struct Node * right;
         
 int weight;
 char huffcode;
 //哈夫曼编码 对于 ascii 表 128 最长8位,最短1位
 char huff[9];
} * lnode;
//全部ASCII字符
#define ASCII_SUM 128
//字母表
#define CHARS_SUM 26
//主算法
void huffuman( int weight[]);
//计算权值
void calculate_weight();
//构建haffman树
void Insert_node(lnode *tail, lnode head, lnode cur);
//构建一个节点
lnode make_node( int value, int weight);
//输出编码
void output( lnode root, int h, char *huff);

int 
main (void ){
 int weight[CHARS_SUM], i ;
 for ( i=0; i<CHARS_SUM; i++ ){
  weight[i] = 0;
 }
 calculate_weight(weight); 
 huffuman(weight);
}

void calculate_weight(int weight[]){
 int n;
 char buf[1024];
 char * pos;
 //手动输入,可改写为文件输入
 while ( scanf("%s", buf) !=EOF){
  pos = buf;
  n = strlen(buf);
  while ( pos < buf + n ){
   //对应各自数组位
   weight[*(pos++)-'a']++;
   
  }
 }
}
/*待编码列表是个降序排列的链表 头结点是head , 尾节点为tail
  有新节点按序插入, 则队列最后两个节点总是要合并的两个最小权值子树
*/
void huffuman( int weight[]){
 int i=0, top = -1;
 struct Node head;
 head.parent = NULL;
 lnode tail = &head, cur, temp, s1, s2;
 //构建一个有26数的森林
 for (i=0;i<CHAS_SUM;i++){
  if (weight[i]!=0){
   cur = make_node(i, weight[i]);
   Insert_node( &tail, &head, cur );
  }
 }
 /*将两最小子树合并,并插入降序链表,循环构建 ,
 *如果链表中只有一个节点,构建完成
 */
 s1 = tail;
 s2 = s1->parent;
 //如果地址为头结点 则链表中只有s1一个节点 结束循环
 while ( s2 != &head ){
  tail = s2->parent;
  //构建新节点
  cur = make_node(-1, s1->weight + s2->weight);
  cur->left = s2;
  cur->right = s1;
  Insert_node(&tail, &head, cur );
  s1 = tail;
  s2 = s1->parent;
 }
 output (tail, -1, tail->huff);
}

void Insert_node(lnode *tail, lnode head, lnode cur){
 lnode index = *tail, pre=NULL;
 //如果空表,则插入返回
 if ( *tail == head ){
  cur->parent = head;
  *tail= cur;
  return;
 }
 index = *tail;
 while( index != head ){
  //排序插入
  if ( index->weight > cur->weight ){
   if ( pre == NULL ){
    cur->parent = index;
    *tail = cur;
   }
   else{
    pre->parent = cur;
    cur->parent = index;
   }
   return;
  }
  pre = index;
  index = pre->parent;
  }
 cur->parent = head;
 pre->parent = cur;
}
lnode make_node( int value, int weight){
 lnode  nnode;
 nnode = (lnode)malloc( sizeof(struct Node) );
 nnode->left = NULL;
 nnode->right = NULL;
 nnode->parent = NULL;
 nnode->value = value;
 nnode->weight = weight;
 return nnode;
}
void output( lnode root, int h, char *huff){
 int i =0, d;
 if (root == NULL){
  return;
 }
 strncpy(root->huff, huff, 32);
 //判断左孩子,还是右孩子 加入不同的编码值
 if ( h == 0){
  d = strlen(root->huff);
  *(root->huff+d)='0';
  *(root->huff+d+1) ='/0';
 }
 else if ( h==1){
  *(root->huff+d)='1';
  *(root->huff+d+1) ='/0';
 }
 if ( root->left ==NULL && root->right==NULL){
  printf("%s : %c/n", root->huff, root->value+'a');
  return;
 }
 output( root->left, 0,root->huff);
 output( root->right,1,root->huff );
}

原创粉丝点击