经典压缩方法-哈夫曼编码

该博客详细介绍了哈夫曼编码的原理及其在数据压缩中的应用。通过使用最优二叉树,即哈夫曼树,构建了哈夫曼编码,并提供了C++实现的代码示例,包括创建哈夫曼树、构建哈夫曼编码表、编码和解码的过程,以及计算带权路径长度。此外,还给出了一个简单的示例来演示编码和解码的流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

哈夫曼编码

应用

哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩

实现思路

采用二叉树建立哈夫曼树

在这里插入图片描述

首先,队列中存放所哈夫曼树节点

  1. 创建一个哈夫曼树节点p
  2. p的左孩子为队列权值最小的节点a,然后a出队
  3. p的右孩子为队列权值最小的节点b,然后b出队
  4. p入队
  5. 重复1、2、3、4,直到队列中只剩下一个节点,这个节点为哈夫曼树的root

huffman.h

#include <iostream>
#include <list>
#include <stdio.h>
#include <string>
#include <map>
#define HfmElemType char
using namespace std;
//哈夫曼树节点
typedef struct HfmLeafNode
{
  HfmElemType Symbol;
  int Weight;
  HfmLeafNode *lchild, *rchild;
} HfmLeafNode, *HfmTree;
//构建哈夫曼树中,取权值频率最小的排序
bool Order(HfmLeafNode d1, HfmLeafNode d2)
{
  //排序
  return d1.Weight < d2.Weight;
}
//初始化节点数据
HfmTree InitNode(HfmLeafNode &Node);
//构建哈夫曼树
HfmTree CreateHuffman(list<HfmLeafNode> &List);
//构建哈夫曼编码表
bool CreateHfmTable(map<int, string> &M);
//编码
bool Encode(HfmTree T, int index, string code, map<int, string> &M);
//解码
bool Decode(HfmTree T, string code);
//计算带权路径长度
void GetWPL(map<int, string> m);

huffman.cpp

#include "huffman.h"
//初始化节点
HfmTree InitNode(HfmLeafNode &Node)
{
  Node.lchild = Node.rchild = NULL;
  Node.Symbol = '#';
  Node.Weight = 0;
  return &Node;
}

void Copy(HfmTree T, HfmLeafNode node)
{
  T->Symbol = node.Symbol;
  T->Weight = node.Weight;
  T->lchild = node.lchild;
  T->rchild = node.rchild;
}
//构建哈夫曼树
HfmTree CreateHuffman(list<HfmLeafNode> &List)
{
  List.sort(Order);
  while (List.size() != 1)
  {
    HfmTree T = new HfmLeafNode;
    HfmTree Left = new HfmLeafNode;
    HfmTree Right = new HfmLeafNode;
    T = InitNode(*T);
    //复制节点数据,因为List删除节点会清空数据
    Copy(Left, List.front());
    //权值最小成为左孩子
    T->lchild = Left;
    T->Weight = Left->Weight;
    //出队
    List.pop_front();
    //权值第二小成为右孩子
    Copy(Right, List.front());
    T->rchild = Right;
    T->Weight += List.front().Weight;
    //出队
    List.pop_front();
    //形成新的节点入队
    List.push_front(*T);
    //再根据权值大小排序
    List.sort(Order);
  }
  return &List.front();
}
//构建哈夫曼编码表
bool CreateHfmTable(int weight, string code, map<int, string> &M)
{
  M.insert(pair<int, string>(weight, code));
  return true;
}
//解码
bool Decode(HfmTree T, string code)
{
  printf("解码结果:");
  HfmTree temp = T;
  for (int i = 0; i < code.length(); i++)
  {
    int c = (int)code[i] - 48; //字符转数字
    if (c < 0 || c > 1)
    {
      printf("编码错误!\n");
    }
    if (c == 0 && temp->lchild != NULL)
    {
      temp = temp->lchild;
    }
    else if (c == 1 && temp->rchild != NULL)
    {
      temp = temp->rchild;
    }
    if (temp->Symbol != '#')
    {
      cout << temp->Symbol;
      temp = T;//重新遍历哈夫曼树
    }
  }
  cout << endl;
  return true;
}
//编码,从root自顶向下递归遍历
bool Encode(HfmTree T, int index, string code, map<int, string> &M)
{
  if (T->lchild == NULL && T->rchild == NULL)
  {
    code = code.substr(0, code.find("-")); //字符串切片0到-
    cout << T->Symbol << ":" << code << endl;
    CreateHfmTable(T->Weight, code, M);
  }
  if (T->lchild != NULL)
  {
    code[index] = '0';
    Encode(T->lchild, index + 1, code, M);
  }
  if (T->rchild != NULL)
  {
    code[index] = '1';
    Encode(T->rchild, index + 1, code, M);
  }
  return true;
}
//获取WPL
void GetWPL(map<int, string> m)
{
  int wpl = 0;
  for (map<int, string>::iterator it = m.begin(); it != m.end(); it++)
  {
    cout << "weight=" << it->first << " code=" << it->second << endl;
    wpl += it->first * it->second.length();
  }
  cout << "WPL:" << wpl << endl;
}

int main()
{
  // a 45 c 12 b 13 f 5 e 9 d 16
  // f 25 e 18 d 9 a 2 b 3 c 7
  //节点队列
  list<HfmLeafNode> L;
  //哈夫曼编码表
  map<int, string> M;
  for (int i = 0; i < 6; i++)
  {
    HfmLeafNode h;
    cin >> h.Symbol >> h.Weight;
    h.lchild = h.rchild = NULL;
    L.push_back(h);
  }
  HfmTree T = CreateHuffman(L);
  printf("编码结果:\n");
  string code = "-------";
  Encode(T, 0, code, M);
  string decode = "0101100111110111000101111";
  Decode(T, decode);
  GetWPL(M);
  return 0;
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值