Huffman树及Huffman编码的算法实现

Huffman树及Huffman编码的算法实现(必做,验证性实验)

实验目的

熟悉掌握Huffman树的构造方法及Huffman编码的应用,了解Huffman树在通信、编码领域的应用过程。
实验内容
(1)输入一段100—200字的英文短文,存入一文件a中。
(2)写函数统计短文出现的字母个数n及每个字母的出现次数
(3)写函数以字母出现次数作权值,建Haffman树(n个叶子),给出每个字母的Haffman编码。
(4)用每个字母编码对原短文进行编码,码文存入文件b中。
(5)用Haffman树对文件b中码文进行译码,结果存入文件c中,比较a,c是否一致,以检验编码、译码的正确性。
数据结构定义
算法中使用的数据结构是链表,用链表来创建哈夫曼树,哈夫曼树中的每一个节点中出现的元素有每一个节点的权值,以及该节点的双亲,左孩子以及右孩子。然后又创建了一个node类型的节点用来存储字符以及字符的信息。
同时,为了方便大小比较以及排序,我定了一个vector容器,方便之后的操作。

#include "constant.h"
#include <stdio.h>
#include <string.h>
typedef char **huffmancode;
#define maxsize 300
#define INF 1e5
typedef struct
{
  /* data */
  int weight;
  int parent, lchild, rchild;
} HTNode, *huffmantree;
typedef struct node
{
  char ch;
  int data;
} node;

void createhuffmantree(huffmantree &HT, huffmancode &HC, int *w, int n); //创建哈夫满树
void huffmancoding(huffmantree &HT, huffmancode &HC, int *w, int n);     //对哈夫曼树进行编码,找到其对应的哈夫曼编码
void select(huffmantree HT, int length, int &s1, int &s2);               //挑选出权值最小的两个数
void read(int weight[maxsize], int &length);                             //将数组中的权值读入权值数组中
void count();
void compare();
void translate();
 
算法思想及算法设计
void select(huffmantree HT, int length, int &s1, int &s2)
{
   //s1存储权制最小的节点,s2存储第二小的节点
   if (length <= 2)
       exit(0);
   int s1a = 9999999, s2a = 9999999; //默认存储前两个个数
   for (int k = 1; k <= length; k++)
   {
       if (HT[k].parent == 0) //不断进行优化,找出最好的,最方便的优化结果,优化方案
       {
           if (HT[k].weight < s1a) //先找到最小的节点
           {
               s1a = HT[k].weight;
               s1 = k;
           }
       }
   }
   for (int k = 1; k <= length; k++)
   {
       if (HT[k].parent == 0) //不断进行优化,找出最好的,最方便的优化结果,优化方案
       {
           if (HT[k].weight < s2a && HT[k].weight != s1a)
           {
               s2a = HT[k].weight;
               s2 = k;
           }
       }
   }
}
void pr(node a)
{
   cout << a.ch << " " << a.data << endl;
}
void print(pair<char, int> v)
{
   //cout<<v.first<<" "<<v.second<<endl;
   node temp = {v.first, v.second};
   v1.push_back(temp);
}
void read(int weight[maxsize], int &length, char weightch[maxsize])
{
   weight[maxsize] = {0};
   FILE *fp;
   multimap<char, int> wgh;
   fp = fopen("shiyanshuju.txt", "r");
   char ch = fgetc(fp);
   while (ch != EOF)
   {
       if (wgh.find(ch) == wgh.end())
       {
           wgh.insert(make_pair(ch, 1));
       }
       else
       {
           wgh.find(ch)->second++;
       }
       ch = fgetc(fp);
   }
   fclose(fp);
   for_each(wgh.begin(), wgh.end(), print);
   vector<node>::iterator its = v1.begin();
   for (int i = 0; i < v1.size(); i++)
   {
       for (int j = i + 1; j < v1.size(); j++)
       {
           if (v1[i].data <= v1[j].data)
           {
               node temp = v1[j];
               v1[j] = v1[i];
               v1[i] = temp;
           }
       }
   }
   //for_each(v1.begin(), v1.end(), pr);
   int i = 1;
   length = wgh.size();
   its = v1.begin();
   while (its != v1.end())
   {
       weight[i] = its->data;
       weightch[i] = its->ch;
       its++;
       i++; //别乱加
   }
   return;
}

void createhuffmantree(huffmantree &HT, huffmancode &HC, int *w, int n)
{
   if (n <= 1) //创建哈夫曼树,然后后面是秋哈夫曼编码
   {
       return;
   }
   int m = 2 * n - 1;
   huffmantree p;
   int i = 0;
   int s1, s2;
   w++;
   HT = (huffmantree)malloc((m + 1) * sizeof(HTNode));
   for (p = HT, i = 1; i <= n; i++, ++p, ++w)
   {
       *p = {*w, 0, 0, 0};
   }
   for (; i <= m; i++, ++p)
   {
       *p = {0, 0, 0, 0};
   }
   for (i = n + 1; i <= m; i++)
   {
       select(HT, i - 1, s1, s2);
       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;
   }
}
void huffmancoding(huffmantree &HT, huffmancode &HC, int *w, int n)
{ //进行哈夫曼编码
   int i = 0;
   //从叶子到根逆向求哈夫曼编码
   HC = (huffmancode)malloc((n + 1) * sizeof(char *));
   char *cd = (char *)malloc(n * sizeof(char));
   cd[n - 1] = '\0';
   int start;
   for (i = 1; i <= n; i++)
   {
       start = n - 1;
       for (int c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
       {

           if (HT[f].lchild == c)
               cd[--start] = '0';
           else
               cd[--start] = '1';
       }
       HC[i] = (char *)malloc((n - start) * sizeof(char));
       strcpy(HC[i], &cd[start]);
   }
   free(cd);
}
void bianma(huffmancode &HC, char weightch[maxsize])
{
   FILE *fp1, *fp2;
   fp1 = fopen("bianma.txt", "w");      //写文件
   fp2 = fopen("shiyanshuju.txt", "r"); //读文件
   char ch = fgetc(fp2);
   while (ch != EOF)
   {
       int i = 1;
       while (weightch[i] != ch && weightch[i] != '\n')
       {
           i++;
       }
       fprintf(fp1, "%s", HC[i]);
       ch = fgetc(fp2);
   }
   fclose(fp1);
   fclose(fp2);
}
void jiema(huffmantree HT, char weightch[maxsize], int m)
{
   FILE *fp;
   char ch = '\n';
   fp = fopen("bianma.txt", "r");
loop:
   int i = m;
   while (HT[i].lchild != 0 && HT[i].rchild != 0)
   {
       ch = fgetc(fp);
       if (ch == EOF)
       {
           fclose(fp);
           return;
       }
       if (ch == '1') //注意这里的左右对应关系
           i = HT[i].rchild;
       else
           i = HT[i].lchild;
   }
   printf("%c", weightch[i]);
   goto loop;
}
实验代码

部分算法已在上面给出:
下面是为给出的连接部分:

#ifndef constant_h
#define constant_h
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;

#endif /* constant_h */

#include <stdio.h>
#include <iostream>
#include "huffmancode.hpp"
#include "constant.h"
#include <stdlib.h>
#include <string.h>
#include <string>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
void huffmancoding(huffmantree &HT, huffmancode &HC, int *w, int n);
void select(huffmantree HT, int length, int &s1, int &s2);
void read(int weight[maxsize], int &length, char weightch[maxsize]);
void huffmancoding(huffmantree &HT, huffmancode &HC, int *w, int n);
void createhuffmantree(huffmantree &HT, huffmancode &HC, int *w, int n);
void huffmancoding(huffmantree &HT, huffmancode &HC, int *w, int n);
void bianma(huffmancode &HC, char weightch[maxsize]);
void jiema(huffmantree HT, char weightch[maxsize], int m);
vector<node> v1;

int main()
{
   int length = 0;
   huffmantree HT;
   huffmancode HC;
   int weight[maxsize] = {0};
   char weightch[maxsize] = {'\n'};
   read(weight, length, weightch);
   createhuffmantree(HT, HC, weight, length);
   huffmancoding(HT, HC, weight, length);
   bianma(HC, weightch);
   int m = length * 2 - 1;
   printf("把哈夫曼编码解码可得:\n");
   jiema(HT, weightch, m);
}

算法测试结果

以下为测试文档内容:

分析与总结

(1)算法复杂度分析及优、缺点分析
哈夫曼编码的创建过程中的时间复杂度为:O(n),哈夫曼过程中涉及的排序操作是采用快排序,时间复杂度为O(nlog⁡n),哈夫曼编码在创建过程中就采用最优方法,将权值最大的节点放在靠近根节点的位置,使得编码之后的哈夫曼编码变得简单,而且没有二义性,非常简单
(2)实验总结
在编写select函数时 ,不能迅速找到方法,在认真思考以及修改之后找到了寻找出最大的两个节点。
刚开始在读取实验数据文档的时候不能迅速的对应每个字母,每一个字母都出现了乱码,我刚开始找了好久,也没找到,最终看见有一个地方读取键盘输入信息的时候把那回车键也输入进去,导致出现了很多错误。而且对应排序之后的数组,不能迅速找到对应,经过几番周折,最终利用vector容器找到解决办法。
在最后解码的时候,把左右子树对应的0,1代码搞反,导致整片文档翻译出的东西一个也对不上,导致出现很多乱码。后来在慢慢找错误的时候找到错误的地方。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Huffman是一种用于数据压缩的算法,它通过构一棵二叉实现。在构Huffman的过程中,我们需要先将待压缩的数据按照出现频率从小到大排序,然后将频率最小的两个数据合并成一个节点,该节点的权值为两个数据的权值之和。接着,将新节点插入到已排序的数据中,重新排序,重复以上步骤,直到只剩下一个节点,这个节点就是Huffman的根节点。 Huffman编码是一种将字符编码为二进制的算法,它利用Huffman的结构来实现。在Huffman中,左子表示,右子表示1,从根节点到叶子节点的路径就是该字符的编码编码的长度取决于该字符在Huffman中的深度,出现频率越高的字符编码越短。 Huffman编码算法实现步骤如下: 1. 统计每个字符出现的频率,并按照频率从小到大排序。 2. 将频率最小的两个字符合并成一个节点,该节点的权值为两个字符的权值之和。 3. 将新节点插入到已排序的字符中,重新排序。 4. 重复步骤2和3,直到只剩下一个节点,这个节点就是Huffman的根节点。 5. 遍历Huffman,生成每个字符的编码。 6. 将编码存储起来,用于解码时的还原。 以上就是Huffman树及Huffman编码算法实现。 ### 回答2: Huffman是一种用来进行数据压缩的算法,它基于字符出现的频率来构一棵,从而生成一种特殊的编码方式——Huffman编码Huffman编码是一种非常高效的压缩方式,可以让数据在传输或存储时占用更少的空间。 Huffman的构过程非常简单,可以分为以下几步: 1. 统计每个字符出现的频率,根据频率从小到大排序。 2. 取出频率最小的两个字符,合并成一个新节点,并将新节点的频率设置为这两个字符的频率之和。新节点的左节点为频率小的字符,右节点为频率大的字符。 3. 重复步骤2,直到只剩下一个节点,此节点即为Huffman的根节点。 在构Huffman完成后,就可以得到每个字符的Huffman编码Huffman编码的规则是:左子节点表示0,右子节点表示1。从根节点开始,沿着每个字符所在路径的方向记录0或1,然后组成一个二进制数就是该字符的Huffman编码。 在实现Huffman编码时,我们可以通过一个哈希表来存储每个字符的出现频率,然后将哈希表中的数据插入到一个优先队列中,优先队列中的元素按照频率从小到大排序。接下来,我们可以按照上述步骤来构Huffman,最后得到每个字符的Huffman编码。我们可以将Huffman编码存储到另一个哈希表中,这样我们就可以将原始数据按照Huffman编码来进行压缩了。 Huffman编码是一种很好的数据压缩方式,它可以大大减少数据在传输和存储时所占用的空间。Huffman的构Huffman编码实现并不难,只需要遵循一定的规则,就可以得到正确的结果。 ### 回答3: Huffman是一种基于贪心算法的数据压缩方式,通过构哈夫曼(也称最优二叉),来实现对数据的压缩和解压缩。其编码方式被广泛应用于压缩文件、图像和视频等多种媒体数据。 哈夫曼是一种带权(也称为加权),每个节点带有权值(也称为频率),根到叶子节点的路径表示一个字符的编码。哈夫曼的构造需要完成三个步骤: 1. 将给定字符集中的每个字符,按照出现频率从小到大进行排序; 2. 依次选取出现频率最小的两个字符,创一个新节点,将这两个节点为其子节点,将新节点的权值设为这两个节点的权值之和; 3. 重复步骤2,直到只剩下一个节点,此节点即为哈夫曼的根节点。 构造好哈夫曼后,通过遍历,得到每个字符的编码。具体方法是从根节点开始,如果遇到左子节点就在当前编码的末尾添加0,如果遇到右子节点就添加1,直到到达叶子节点,此时就得到了该字符对应的编码。在编码时,为了避免出现字符编码相同的情况,要求每个字符编码不是任何一个字符编码的前缀。 Huffman编码实现主要有两个步骤:构哈夫曼和生成编码。在构哈夫曼时,需要使用堆这个数据结构来维护出现频率最小的两个字符。在生成编码时,可以通过深度优先遍历递归来实现。 使用哈夫曼编码可以将一组字符压缩成相应的位序列,可以大大减小存储和传输数据所需的空间和时间。然而,哈夫曼编码虽然可以解决数据压缩的问题,但一旦数据被压缩,就需要解压缩才能使用,而解压缩的过程中会消耗一定的时间和计算资源。此外,当压缩目标文件内容比较零散,分布比较分散时,使用哈夫曼编码并不能得到较好的压缩效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值