C语言实现哈夫曼树

 更新时间:2020年04月28日 10:42:29   作者:小1懒鱼  
这篇文章主要为大家详细介绍了C语言实现哈夫曼树,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了C语言实现哈夫曼树的具体代码,供大家参考,具体内容如下

//哈夫曼树C语言实现
#include <stdio.h>
#include <stdlib.h>
typedef struct HuffmanNode
{
 char letter;//存储的字符,叶节点为字母,非叶节点为#
 struct HuffmanNode *parent;//父亲结点
 int code;//如果为父亲结点的左孩子,则为0,右孩子为1
}HuffmanNode;
typedef struct HeapNode
{
 int rate;//出现频率
 HuffmanNode *node;//对应于哈夫曼树中的结点
}HeapNode;
/*------------------全局变量----------------------*/
int heapSize;//堆大小
int num;//记录字符数量
HeapNode *heap;//堆数组
char *letter;//字符数组
int *rate;//字符出现频率
HuffmanNode **array; //记录叶节点的数组,打印编码的时候可以从叶结点回溯向上
char ch;
/*----------------------函数声明-------------------------*/
void init(int numOfLetters);//初始化变量
void input();//输入数组
int parent(int i);//求父节点
int left(int i);//求左孩子
int right(int i);//求右孩子
void swap(int i,int j);//交换函数
void heapIfy(int i,int localHeapSize);//维持堆性质函数,使用前提为左右子树均为最小堆
void buildHeap();//初始化堆
HeapNode* extractMin();//去掉并返回堆中最小的元素
void heapInsert(int rate,HuffmanNode *p);//向堆中插入数据(前提:堆已经初始化)
HuffmanNode* buildTree();//构造哈夫曼树
void display();//显示函数
void backPrint(HuffmanNode *p,HuffmanNode *root);//从叶节点回溯打印编码code
/*----------------------函数实现-------------------------*/
void init(int numOfLetters)
{
 heapSize=numOfLetters;//堆大小初始化为字母数
 num=numOfLetters;//记录字符数量
 heap=(HeapNode*)malloc((numOfLetters+1)*sizeof(HeapNode));//分配堆空间,最多只需要字符的个数,因为合并过程中删除两个,插入一个
 letter=(char*)malloc((numOfLetters+1)*sizeof(char));//用于存储字符
 rate=(int *)malloc((numOfLetters+1)*sizeof(int));//用于存储字符出现频率
 array=(HuffmanNode **)malloc((numOfLetters+1)*sizeof(HuffmanNode));//记录叶节点的数组,打印编码的时候可以从叶结点回溯向上
 
}
void input()
{
 int i=1;
 while(i<=heapSize)
 {
  printf("输入第%d个字符\n",i);
  scanf("%c",&letter[i]);ch=getchar();
  printf("输入第%d个字符的频度\n",i);
  scanf("%d",&rate[i]);ch=getchar();
  //向堆中插入各个结点
  heap[i].rate=rate[i];
  heap[i].node=(HuffmanNode *)malloc(sizeof(HuffmanNode));
  array[i]=heap[i].node;
  heap[i].node->parent=NULL;
  heap[i].node->letter=letter[i];
  i++;
 }
}
int parent(int i)
{
 return i/2;
}
int left(int i)
{
 return 2*i;
}
int right(int i)
{
 return 2*i+1;
}
void swap(int i,int j) //交换结构体数组,需要交换结构体内数据
{
 int rate;
 HuffmanNode *p;
 rate=heap[i].rate;
 p=heap[i].node;
 heap[i].rate=heap[j].rate;
 heap[i].node=heap[j].node;
 heap[j].rate=rate;
 heap[j].node=p;
}
void heapIfy(int i,int localHeapSize)//维持堆性质函数,使用前提为左右子树均为最小堆
{
 int l=left(i);
 int r=right(i);
 int least=i;
 //找出heap成员rate 的i,left(i),right(i)的最小值
 if(l<=localHeapSize&&heap[least].rate>heap[l].rate)
 {
  least=l;
 }
 if(r<=localHeapSize&&heap[least].rate>heap[r].rate)
 {
  least=r;
 }
 if(least!=i)
 {
  swap(i,least);
  heapIfy(least,localHeapSize);
 }
}
void buildHeap()//初始化堆
{
 int i=0;
 for(i=heapSize/2;i>=1;i--)
 {
  heapIfy(i,heapSize);
 }
}
HeapNode* extractMin()
{
 if(heapSize>=1)
 {
  HeapNode *min;
  swap(1,heapSize);
  min=&heap[heapSize];
  --heapSize;
  heapIfy(1,heapSize);
  return min;
 }
 else
 {
  printf("堆中没有元素");
  return NULL;
 }
}
void heapInsert(int rate,HuffmanNode *p)
{
 ++heapSize;
 int i=heapSize;
 while(i>1&&heap[parent(i)].rate>rate)
 {
  heap[i].rate=heap[parent(i)].rate;
  heap[i].node=heap[parent(i)].node;
  i=parent(i);
 }
 heap[i].rate=rate;
 heap[i].node=p;
}
HuffmanNode* buildTree()
{
 buildHeap();//初始化堆
 HeapNode *p;//用于临时存储最小堆结点
 HeapNode *q;//用于临时存储次小堆结点
 int count=heapSize;
 int i;
 for(i=1;i<=count-1;i++)
 {
  HuffmanNode *tree=(HuffmanNode*)malloc(sizeof(HuffmanNode));//生成内结点
  tree->letter='#';//内结点的字符记作#,没有实际意义
  p=extractMin();
  q=extractMin();
  p->node->parent=tree;
  p->node->code=0;
  q->node->parent=tree;
  q->node->code=1;
  //printf("%c:%d",p->node->letter,p->node->code);
  //printf("\n"); printf("%c:%d",q->node->letter,q->node->code); printf("\n");//测试
  heapInsert(p->rate+q->rate,tree);//插入堆中
 }
 return extractMin()->node;
}
void display()
{
 HuffmanNode*p=buildTree();////哈夫曼树的根节点地址
 int i=1;
 while(i<=num)
 {
  printf("%c:",array[i]->letter);
  backPrint(array[i],p);
  printf("\n");
  i++;
 }
}
void backPrint(HuffmanNode *p,HuffmanNode *root)
{
 if(p!=root)
 {
  backPrint(p->parent,root);
  printf("%d",p->code);//printf("++++");//测试
 }
}
int main(int argc ,char* argv[])
{
 int number;
 printf("输入的字符个数为:\n");
 scanf("%d",&number);
 ch=getchar();
 init(number);
 input();
 display();
 system("PAUSE");
 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 深入C++四种强制类型转换的总结

    深入C++四种强制类型转换的总结

    本篇文章是对C++中四种强制类型转换进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • QT中窗口关闭自动销毁的实现示例

    QT中窗口关闭自动销毁的实现示例

    这篇文章主要介绍了QT中窗口关闭自动销毁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • C中实现矩阵乘法的一种高效的方法

    C中实现矩阵乘法的一种高效的方法

    本篇文章介绍了,在C中实现矩阵乘法的一种高效的方法。需要的朋友参考下
    2013-05-05
  • C语言实现循环队列

    C语言实现循环队列

    这篇文章主要为大家详细介绍了C语言实现循环队列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • Qt 使用Poppler实现pdf阅读器的示例代码

    Qt 使用Poppler实现pdf阅读器的示例代码

    下面小编就为大家分享一篇Qt 使用Poppler实现pdf阅读器的示例代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • C++使用grpc实现回射服务器

    C++使用grpc实现回射服务器

    gRPC是由Google开发的一个开源的高性能远程过程调用(RPC)框架,用于在分布式系统中实现跨语言的服务通信,本文我们就来看看C++如何使用grpc实现回射服务器
    2024-10-10
  • C++实现中值滤波的示例代码

    C++实现中值滤波的示例代码

    本文主要介绍了C++实现中值滤波的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 浅析C++元组tuple类型

    浅析C++元组tuple类型

    元组tuple是C++的一个模板,不同tuple类型的成员类型也不相同,但是一个tuple可以有任意数量的成员,今天通过本文给大家介绍C++元组tuple类型,感兴趣的朋友一起看看吧
    2022-06-06
  • Matlab实现将图像序列合并为视频的方法详解

    Matlab实现将图像序列合并为视频的方法详解

    MATLAB是一种高性能语言,用于操纵矩阵、执行技术计算、绘图等。它代表矩阵实验室。借助这个软件,我们可以从图像中创建视频。这篇文章主要介绍了Matlab实现将图像序列合并为视频的四个方法,希望对大家有所帮助
    2023-03-03
  • 浅谈C++ 缓冲区(buffer)的使用

    浅谈C++ 缓冲区(buffer)的使用

    缓冲区是用来存放流中的数据,本文详细的介绍了C++ 缓冲区(buffer)的使用,感兴趣的小伙伴们可以参考一下
    2021-06-06

最新评论