哈夫曼编码生成哈夫曼树

//哈夫曼编码/
/* //maxnode = 2*n-1
哈夫曼编码:从队列中取出权重最小的两个节点,进行构造树
   将新生成的节点作为父节点
   
使用结构体:
  Node(node1,node2,weight)   //权重边信息保存
  HuffmanTree(weight,family,lchild,rchild)   //存储哈夫曼树
    HTQueue(ht[],front,rear)   //队列处理生成哈夫曼树
    
函数说明:
CreatHT (HuffmanTree ht,Node node[]) //在队列中构造哈夫曼树
 输入:Node node[]  //权重信息
    int e  //权重边数
 输出:返回构造的哈夫曼树
函数简析: 
 初始化队列
 while rear != front        //队列不空
  if  front-rear == 1   return  //只有一个元素   
  else get the 2 min-weight to deal() //取出权重最小的两个节点进行处理
    
deal (HTQueue &qt,int min1,int min2)  //处理队列中的哈夫曼数节点排序情况
  输入: HTQueue &qt   //当前待处理队列的引用
     int min1,int min2 //当前队列中权重最小的两个节点
 输出:重新排序的队列
  */

#include <stdio.h>
#include <iostream>
#define MAXN 10  //叶子节点最大数
typedef struct
{
 int node1;  //节点1
 int node2;  //节点2
 int weight; //权重
}Node;   //保存节点间路径
typedef struct HMTree
{
 Node node;   //权重边信息
 int family; //父节点
 int lchild; //左孩子
 int rchild; //右孩子 
}HuffmanTree;   //哈夫曼树树形存储
typedef struct
{
 HuffmanTree ht[2*MAXN-1]; //待处理队列
 int front,rear;     //队首,队尾
} HTQueue;   //处理队列
void getNode (Node node[],int e);
void disp (HTQueue t,int start);
//哈夫曼编码/
HTQueue CreatHT (Node node[],int e);
void deal (HTQueue &qt,int min1,int min2);
///
int main ()
{
//输入样例
 //5 10 0 0 0 0 1 8 0 3 5 1 1 0 1 2 3 2 2 0 2 4 6 3 1 9 3 3 0 4 4 0
 /*
  6 10
  0 1 6 
  0 2 1 
  0 3 5 
  1 4 3 
  1 2 5 
  2 3 5 
  2 5 4 
  2 4 6 
  3 5 2 
  4 5 6
 */
 int n,e;
 printf ("请输入顶点数和边数:");
 scanf ("%d %d",&n,&e);
 Node node[e];
 HTQueue ht;
 getNode (node,e);
 printf ("\n");
 ht = CreatHT (node,e);
 printf ("生成的哈夫曼树为:");
 disp (ht,ht.front-1);
 printf ("\n");
 return 0;
}
void getNode (Node node[],int e)
{
 int i;
 for (i=0; i<e; i++)
 {
  printf ("请输入第%d组连接顶点x,y与权重w:",i+1);
  scanf ("%d %d %d",&node[i].node1,&node[i].node2,&node[i].weight);
 } 
}
void disp (HTQueue t,int start)
{
 printf ("%d",t.ht[start].node.weight);
 if (t.ht[start].lchild!=-1 && t.ht[start].rchild!=-1)
 {
  printf ("(");
  disp (t,t.ht[start].lchild);
  printf (",");
  disp (t,t.ht[start].rchild);
  printf (")");
 } 
}
void deal (HTQueue &qt,int min1,int min2)
{
 HuffmanTree ht;
 //初始化新节点权重值
 qt.ht[qt.front].node.weight = qt.ht[min1].node.weight + qt.ht[min2].node.weight;
 //将权重最小的两个节点放到当前处理队列最前面,并完善父子关系
 if (qt.rear==min1) //如果权重最小的节点中较大的在当前处理队列的第一位
 { //eg:2 3 1转化为1 2 3。 ht=3; 3=2; 2=1; 1=ht  (1 2 3表示位置)
  ht = qt.ht[qt.rear+1]; //记录第二位
  qt.ht[qt.rear+1] = qt.ht[qt.rear]; //将第二位换为第一位min1
  qt.ht[qt.rear] = qt.ht[min2];//将第一位换为 min2节点
  qt.ht[min2] = ht;   //将记录的位放入原min2位置    
 }
 else
 { //eg:3 4 1 2转化为1 2 3 4。ht=2; 2=3; 3=1; 1=4; 4=ht (1 2 3 4表示位置)
  ht = qt.ht[min1];
  qt.ht[min1]= qt.ht[qt.rear];
  qt.ht[qt.rear] = qt.ht[min2];
  qt.ht[min2] = qt.ht[qt.rear+1];
  qt.ht[qt.rear+1] = ht;  
 } 
 qt.ht[qt.front].rchild = qt.rear; //将交换后的队首节点作为队尾节点的左孩子
 qt.ht[qt.front].lchild = qt.rear+1;
 qt.ht[qt.rear].family = qt.front; //将队尾节点作为交换后的队首节点的父亲
 qt.ht[qt.rear+1].family = qt.front; 
 qt.rear += 2; //队首后移
 qt.front++;
}
HTQueue CreatHT (Node node[],int e)
{
 HTQueue qt;
 qt.front = qt.rear = 0;
 int i,j,min1,min2,min3; 
 
 for (i=0; i<e; i++) //初始化队列,将所有节点进队,叶子节点子节点值置-1
 {
  qt.ht[qt.front].node = node[i];
  qt.ht[qt.front].lchild = qt.ht[qt.front].rchild = -1;  
  qt.front ++; 
 }
    
 while (qt.front != qt.rear)//当队列不空
 {
  if (qt.front-qt.rear == 1) //当只剩下一个元素   
   return qt;   
  else  //找出队列里两个权重最小的节点并进行处理
  {
   min1 = qt.rear; min2 = qt.rear+1;  //记录取出节点所在的队列位置
   if (qt.ht[min1].node.weight<=qt.ht[min2].node.weight)
   {
    min3 = min1; min1 = min2; min2 = min3;  //将权重较大的节点队列编号放在min1
   }   
   for (j=qt.rear+2; j<qt.front; j++) //对未排序的队列进行查找两个最小的节点
   {
    if (qt.ht[j].node.weight<qt.ht[min1].node.weight)   //当节点权重小于节点min1的权重
     min1 = j;
    if (qt.ht[min1].node.weight<=qt.ht[min2].node.weight)
    {
     min3 = min1; min1 = min2; min2 = min3;  //将权重较大的节点队列编号放在min1
    }
   }
   deal (qt,min1,min2);  //调用处理函数将队列重新排序
  }   
 } 
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值