文件压缩——哈夫曼树编码(一)

何谓哈夫曼树?——

  百度百科:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

哈夫曼树的应用?——

  哈夫曼编码 与 哈夫曼译码。

哈夫曼树为基础的项目?——

  文件压缩。

文件压缩分两种:1.有损压缩。2.无损压缩。

哈夫曼树为核心算法的压缩方式是无损压缩。

其实我们windows常用的zip类型的压缩包底层,哈夫曼树就是核心算法之一(当然不全是)。

生成一棵哈夫曼树并进行哈夫曼编码,再用哈弗曼编码和哈夫曼树还原——

比如看这条语句:aaaabbbccd

1.首先统计文件字符出现次数——

a 4

b 3

c 2

d 1

2.构建huffman树——见图

  

3.根据huffman树生成huffman编码(huffman code)

  a --- 0   b --- 11 c --- 101  d --- 100

  aaaabbbccd --- 0000111111101101100
4.压缩——
test.txt -----> test.huffman
每一个字符都有唯一的路劲,那么每一个字符都有唯一的编码,那么就可以替换完成无损压缩。
5.解压缩——
使用test.huffman------->test.txt

那么详细的让我们看代码——

.h文件——

该类模拟生成哈夫曼树。

 1 #pragma once
 2
 3 #include<queue>
 4
 5 template<typename W>
 6 struct HuffmanTreeNode
 7 {
 8     W val;
 9     HuffmanTreeNode* right;
10     HuffmanTreeNode* left;
11 };
12
13 //堆——优先级队列。priority_queue
14
15 template<typename W,typename T>
16 class HuffmanTree
17 {
18     //放在内部,方便且安全
19     typedef HuffmanTreeNode Node;
20 public:
21     //优先队列中放的是结点的指针。
22     //因为我放的是指针,但是比较的时候不能比较指针啊。
23     //所以在这里我需要写一个仿函数。
24     //让他用我的仿函数比较。但是要注意,仿函数是第三个模板参数,所以第二个模板参数还是要一样的。
25
26     //因为我们要杜绝出现出现次数为0的情况,这种情况不会被我们统计但是如果不管会占空间。
27     HuffmanTree(W* a,size_t n,const T& invalid);
28
29     //生成完哈夫曼树后那么接下来就是要生成哈夫曼编码了
30     //生成哈夫曼编码的方法
31     //1.三叉链法。添加一个parents指针在HuffmanNode结构体中,并且注意初始化。
32     //2.递归,左0右1。递归方法放在FileCompress类中。
33
34     //因为如果利用递归法,就很有可能需要在最后,将根的哈夫曼码变成当前结点结构体中的哈夫曼码。
35     //所以需要类提供一个接口
36     //返回root
37     Node* GetRoot();
38
39     ~HuffmanTree();
40     //因为涉及树,所以删除很有可能需要调用递归,要自觉习惯用一个函数来完成析构任务。
41     void destory(Node* root);
42 private:
43     //暂时用不到拷贝构造和=运算符重载
44     //所以直接用防拷贝的方法。
45     HuffmanTree(const HuffmanTree<W> &t);
46     HuffmanTree<W>& operator=(const HuffmanTree<T> &t);
47 protected:
48     Node* root;
49 };

HuffmanTree.h

接下来是用例案例——

模拟实现文件解析类。

 1 #pragma once
 2
 3 #include<string>
 4 #include"HuffmanTree.h"
 5 using namespace std;
 6
 7 //一个字符的信息——
 8 //我们会将这个值统计好传过去来生成哈夫曼树。
 9 //但同时我们也知道哈夫曼树中有W的加的操作,>的操作,!=的操作。
10 //所以我们还需要重载+运算符,>运算符,!=运算符。
11 struct CharInfo
12 {
13     char _ch;
14     long long _count;
15     string _code;
16     CharInfo operator+(const CharInfo& info);
17     bool operator>(const CharInfo& info);
18     bool operator!=(const CharInfo& info);
19 };
20
21 class FileCompress
22 {
23 public:
24     //构造函数就是写死,初始化哈希表。
25     FileCompress();
26     //压缩
27     //1.首先要统计文件中字符出现的次数。
28     //2.用IO流的方式读字符串---因为是读,所以是ifstream,因为要从文件里读。
29     //C++reference里有些,构造函数就直接讲字符串当做参数(字符串实际为一个文件),读字符就用get。
30     void Compress(const char *file);
31     //解压缩
32     void Uncompress(const char *file);
33     void GenerateHuffmanCode(HuffmanTreeNode<char> *node);
34 protected:
35     CharInfo _hashInfos[256];//用来存放各个字符。
36 };

FileCompress.h

持续更新...

原文地址:https://www.cnblogs.com/shy0322/p/9201747.html

时间: 2024-10-27 08:39:56

文件压缩——哈夫曼树编码(一)的相关文章

赫夫曼树编码的表示与实现--自己写数据结构

头文件huffman.h #ifndef _HUFFMAN_H_ #define _HUFFMAN_H_ #define MAX_WEIGHT 10000 typedef struct _HTNode { int weight; int parent,lchild,rchild; char data; }HTNode,*pHTNode; typedef char** huffmancode; void select_min_weight(HTNode* btree,int mn,int* s1,

20172303 2018-2019-1《程序设计与数据结构》哈夫曼树编码与解码

20172303 2018-2019-1<程序设计与数据结构>哈夫曼树编码与解码 哈夫曼树简介 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近. 带权路径长度(Weighted Path Length of Tree,简记为WPL) 结点的权:在一些应用中,赋予树中结点的一个有某种意义的实数. 结点的带权路径长度:结点到树根之间的路径长度与

赫夫曼树编码

在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN) 树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如 JPEG中就应用了哈夫曼编码. 首先介绍什么是哈夫曼树.哈夫曼树又称最优二叉树, 是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点 的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度 为叶结点的层数).树的带权路径长度记为WPL= (W1*L1+W2*L2+W3*L3+...+Wn*Ln) ,

C++哈夫曼树编码和译码的实现

一.背景介绍: 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近. 二.实现步骤: 1.构造一棵哈夫曼树 2.根据创建好的哈夫曼树创建一张哈夫曼编码表 3.输入一串哈夫曼序列,输出原始字符 三.设计思想: 1.首先要构造一棵哈夫曼树,哈夫曼树的结点结构包括权值,双亲,左右孩子:假如由n个字符来构造一棵哈夫曼树,则共有结点2n-1个:在构造前,先初始化

看数据结构写代码(32) 赫夫曼树编码以及译码

杂谈:最近有点慵懒,不好不好.好几天都没写代码,原本准备上星期完结 树 这一章节的.现在 又耽误了.哎.要抓紧时间啊. 下面直接上代码: 可以到我的网盘下载源代码,或者 直接拷贝下面的源代码 运行 网盘地址:点击打开链接 // HuffmanTree.cpp : 定义控制台应用程序的入口点. //哈弗曼编码,译码 #include "stdafx.h" #include <stdlib.h> #include <cstring> enum E_State { E

赫夫曼树编码解码实例(C)

//HuffmanTree.h #include <stdlib.h> #include <stdio.h> #include <string.h> #define OVERFLOW -1 typedef struct{ char data; //节点所存字符 unsigned int weight; //节点权重 unsigned int parent,lchild,rchild; }HTNode, *HuffmanTree; //动态分配数组存储赫夫曼树 typed

哈夫曼树的编码实验

Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 建树,造树,编码,解码 一.哈夫曼树编码介绍 1.哈夫曼树: (1)定义:假设有n个权值{w1, w2, ..., wn},试构造一棵含有n个叶子结点的二叉树,每个叶子节点带权威wi,则其中带权路径长度WPL最小的二叉树叫做最优二叉树或者哈夫曼树. (2)特点:哈夫曼树中没有度为1的结点,故由n0 = n2+1以及m= n0+n1+n2,n1=0可推出m=2*n0-1,即一棵有n个叶子节点的哈夫曼树共有2n-1个节点. 2.哈夫曼编码步骤:

数据结构之哈夫曼树

#include <iostream> #include <iomanip> #include <string> using namespace std; typedef struct { string name; int weight; int parent, lchild, rchild; int visited; //设置visited选项来表示每次查找最小权值后的删除,0代表未删除,1表示删除 }HTNode,*HuffmanTree; int Min(Huff

哈夫曼树与哈夫曼编码

哈夫曼树与哈夫曼编码 术语: i)路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径. 路径中分支的数目称为路径长度.若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1. ii)结点的权及带权路径长度 若对树中的每个结点赋给一个有着某种含义的数值,则这个数值称为该结点的权. 结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积. iii)树的带权路径长度 树的带权路径长度:所有叶子结点的带权路径长度之和,记为WPL. 先了解一下