C#,哈夫曼编码(Huffman Code)压缩(Compress )与解压缩(Decompress)算法与源代码
David A. Huffman
哈夫曼编码简史(Huffman code)
1951年,哈夫曼和他在MIT信息论的同学需要选择是完成学期报告还是期末考试。导师Robert M. Fano给他们的学期报告的题目是,寻找最有效的二进制编码。由于无法证明哪个已有编码是最有效的,哈夫曼放弃对已有编码的研究,转向新的探索,最终发现了基于有序频率二叉树编码的想法,并很快证明了这个方法是最有效的。由于这个算法,学生终于青出于蓝,超过了他那曾经和信息论创立者香农共同研究过类似编码的导师。哈夫曼使用自底向上的方法构建二叉树,避免了次优算法Shannon-Fano编码的最大弊端──自顶向下构建树。
1952年,David A. Huffman在麻省理工攻读博士时发表了《一种构建极小多余编码的方法》,一文,它一般就叫做Huffman编码。A Method for the Construction of Minimum-Redundancy Codeshttps://www.ias.ac.in/article/fulltext/reso/011/02/0091-0099
Huffman在1952年根据香农(Shannon)在1948年和范若(Fano)在1949年阐述的这种编码思想提出了一种不定长编码的方法,也称霍夫曼(Huffman)编码。霍夫曼编码的基本方法是先对图像数据扫描一遍,计算出各种像素出现的概率,按概率的大小指定不同长度的唯一码字,由此得到一张该图像的霍夫曼码表。编码后的图像数据记录的是每个像素的码字,而码字与实际像素值的对应关系记录在码表中。
赫夫曼编码是可变字长编码(VLC)的一种。 Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就称Huffman编码。下面引证一个定理,该定理保证了按字符出现概率分配码长,可使平均码长最短。
源程序:
using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
namespace Legalsoft.Truffer.Algorithm
{
/// <summary>
/// 哈夫曼编码的压缩与解压缩
/// </summary>
public class HuffmanCompressor
{
private HuffmanNode oRootHuffmanNode { get; set; } = null;
private List<HuffmanNode> oValueHuffmanNodes { get; set; } = null;
private List<HuffmanNode> BuildBinaryTree(string Value)
{
List<HuffmanNode> oHuffmanNodes = GetInitialNodeList();
Value.ToList().ForEach(m => oHuffmanNodes[m].Weight++);
oHuffmanNodes = oHuffmanNodes
.Where(m => (m.Weight > 0))
.OrderBy(m => (m.Weight))
.ThenBy(m => (m.Value))
.ToList();
oHuffmanNodes = UpdateNodeParents(oHuffmanNodes);
oRootHuffmanNode = oHuffmanNodes[0];
oHuffmanNodes.Clear();
SortNodes(oRootHuffmanNode, oHuffmanNodes);
return oHuffmanNodes;
}
public void Compress(string FileName)
{
FileInfo oFileInfo = new FileInfo(FileName);
if (oFileInfo.Exists == true)
{
string sFileContents = "";
using (StreamReader oStreamReader = new StreamReader(File.OpenRead(FileName)))
{
sFileContents = oStreamReader.ReadToEnd();
}
List<HuffmanNode> oHuffmanNodes = BuildBinaryTree(sFileContents);
oValueHuffmanNodes = oHuffmanNodes
.Where(m => (m.Value.HasValue == true))
.OrderBy(m => (m.BinaryWord))
.ToList();
Dictionary<char, string> oCharToBinaryWordDictionary = new Dictionary<char, string>();
foreach (HuffmanNode oHuffmanNode in oValueHuffmanNodes)
{
oCharToBinaryWordDictionary.Add(oHuffmanNode.Value.Value, oHuffmanNode.BinaryWord);
}
StringBuilder oStringBuilder = new StringBuilder();
List<byte> oByteList = new List<byte>();
for (int i = 0; i < sFileContents.Length; i++)
{
string sWord = "";
oStringBuilder.Append(oCharToBinaryWordDictionary[sFileContents[i]]);
while (oStringBuilder.Length >= 8)
{
sWord = oStringBuilder.ToString().Substring(0, 8);
oStringBuilder.Remove(0, sWord.Length);
}
if (String.IsNullOrEmpty(sWord) == false)
{
oByteList.Add(Convert.ToByte(sWord, 2));
}
}
if (oStringBuilder.Length > 0)
{
string sWord = oStringBuilder.ToString();
if (String.IsNullOrEmpty(sWord) == false)
{
oByteList.Add(Convert.ToByte(sWord, 2));
}
}
string sCompressedFileName = Path.Combine(oFileInfo.Directory.FullName, String.Format("{0}.compressed", oFileInfo.Name.Replace(oFileInfo.Extension, "")));
if (File.Exists(sCompressedFileName) == true)
{
File.Delete(sCompressedFileName);
}
using (FileStream oFileStream = File.OpenWrite(sCompressedFileName))
{
oFileStream.Write(oByteList.ToArray(), 0, oByteList.Count);
}
}
}
public void Decompress(string FileName)
{
FileInfo oFileInfo = new FileInfo(FileName);
if (oFileInfo.Exists == true)
{
string sCompressedFileName = String.Format("{0}.compressed", oFileInfo.FullName.Replace(oFileInfo.Extension, ""));
byte[] oBuffer = null;
using (FileStream oFileStream = File.OpenRead(sCompressedFileName))
{
oBuffer = new byte[oFileStream.Length];
oFileStream.Read(oBuffer, 0, oBuffer.Length);
}
HuffmanNode oZeroHuffmanNode = oRootHuffmanNode;
while (oZeroHuffmanNode.Left != null)
{
oZeroHuffmanNode = oZeroHuffmanNode.Left;
}
HuffmanNode oCurrentHuffmanNode = null;
StringBuilder oStringBuilder = new StringBuilder();
for (int i = 0; i < oBuffer.Length; i++)
{
string sBinaryWord = "";
byte oByte = oBuffer[i];
if (oByte == 0)
{
sBinaryWord = oZeroHuffmanNode.BinaryWord;
}
else
{
sBinaryWord = Convert.ToString(oByte, 2);
}
if ((sBinaryWord.Length < 8) && (i < (oBuffer.Length - 1)))
{
StringBuilder oBinaryStringBuilder = new StringBuilder(sBinaryWord);
while (oBinaryStringBuilder.Length < 8)
{
oBinaryStringBuilder.Insert(0, "0");
}
sBinaryWord = oBinaryStringBuilder.ToString();
}
for (int j = 0; j < sBinaryWord.Length; j++)
{
char cValue = sBinaryWord[j];
if (oCurrentHuffmanNode == null)
{
oCurrentHuffmanNode = oRootHuffmanNode;
}
if (cValue == '0')
{
oCurrentHuffmanNode = oCurrentHuffmanNode.Left;
}
else
{
oCurrentHuffmanNode = oCurrentHuffmanNode.Right;
}
if ((oCurrentHuffmanNode.Left == null) && (oCurrentHuffmanNode.Right == null))
{
oStringBuilder.Append(oCurrentHuffmanNode.Value.Value);
oCurrentHuffmanNode = null;
}
}
}
string sUncompressedFileName = Path.Combine(oFileInfo.Directory.FullName, String.Format("{0}.uncompressed", oFileInfo.Name.Replace(oFileInfo.Extension, "")));
if (File.Exists(sUncompressedFileName) == true)
{
File.Delete(sUncompressedFileName);
}
using (StreamWriter oStreamWriter = new StreamWriter(File.OpenWrite(sUncompressedFileName)))
{
oStreamWriter.Write(oStringBuilder.ToString());
}
}
}
private static List<HuffmanNode> GetInitialNodeList()
{
List<HuffmanNode> oGetInitialNodeList = new List<HuffmanNode>();
for (int i = Char.MinValue; i < Char.MaxValue; i++)
{
oGetInitialNodeList.Add(new HuffmanNode((char)(i)));
}
return oGetInitialNodeList;
}
private static void SortNodes(HuffmanNode Node, List<HuffmanNode> Nodes)
{
if (Nodes.Contains(Node) == false)
{
Nodes.Add(Node);
}
if (Node.Left != null)
{
SortNodes(Node.Left, Nodes);
}
if (Node.Right != null)
{
SortNodes(Node.Right, Nodes);
}
}
private static List<HuffmanNode> UpdateNodeParents(List<HuffmanNode> Nodes)
{
while (Nodes.Count > 1)
{
int iOperations = (Nodes.Count / 2);
for (int iOperation = 0, i = 0, j = 1; iOperation < iOperations; iOperation++, i += 2, j += 2)
{
if (j < Nodes.Count)
{
HuffmanNode oParentHuffmanNode = new HuffmanNode(Nodes[i], Nodes[j]);
Nodes.Add(oParentHuffmanNode);
Nodes[i] = null;
Nodes[j] = null;
}
}
Nodes = Nodes
.Where(m => (m != null))
.OrderBy(m => (m.Weight))
.ToList();
}
return Nodes;
}
}
public class HuffmanNode
{
private string sBinaryWord { get; set; } = "";
private bool bIsLeftNode { get; set; } = false;
private bool bIsRightNode { get; set; } = false;
private HuffmanNode oLeft { get; set; } = null;
private HuffmanNode oParent { get; set; } = null;
private HuffmanNode oRight { get; set; } = null;
private char? cValue { get; set; } = ' ';
private int iWeight { get; set; } = 0;
public HuffmanNode()
{
}
public HuffmanNode(char Value)
{
cValue = Value;
}
public HuffmanNode(HuffmanNode Left, HuffmanNode Right)
{
oLeft = Left;
oLeft.oParent = this;
oLeft.bIsLeftNode = true;
oRight = Right;
oRight.oParent = this;
oRight.bIsRightNode = true;
iWeight = (oLeft.Weight + oRight.Weight);
}
public string BinaryWord
{
get
{
string sReturnValue = "";
if (String.IsNullOrEmpty(sBinaryWord) == true)
{
StringBuilder oStringBuilder = new StringBuilder();
HuffmanNode oHuffmanNode = this;
while (oHuffmanNode != null)
{
if (oHuffmanNode.bIsLeftNode == true)
{
oStringBuilder.Insert(0, "0");
}
if (oHuffmanNode.bIsRightNode == true)
{
oStringBuilder.Insert(0, "1");
}
oHuffmanNode = oHuffmanNode.oParent;
}
sReturnValue = oStringBuilder.ToString();
sBinaryWord = sReturnValue;
}
else
{
sReturnValue = sBinaryWord;
}
return sReturnValue;
}
}
public HuffmanNode Left
{
get
{
return oLeft;
}
}
public HuffmanNode Parent
{
get
{
return oParent;
}
}
public HuffmanNode Right
{
get
{
return oRight;
}
}
public char? Value
{
get
{
return cValue;
}
}
public int Weight
{
get
{
return iWeight;
}
set
{
iWeight = value;
}
}
public static int BinaryStringToInt32(string Value)
{
int iBinaryStringToInt32 = 0;
for (int i = (Value.Length - 1), j = 0; i >= 0; i--, j++)
{
iBinaryStringToInt32 += ((Value[j] == '0' ? 0 : 1) * (int)(Math.Pow(2, i)));
}
return iBinaryStringToInt32;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
if (cValue.HasValue == true)
{
sb.AppendFormat("'{0}' ({1}) - {2} ({3})", cValue.Value, iWeight, BinaryWord, BinaryStringToInt32(BinaryWord));
}
else
{
if ((oLeft != null) && (oRight != null))
{
if ((oLeft.Value.HasValue == true) && (oRight.Value.HasValue == true))
{
sb.AppendFormat("{0} + {1} ({2})", oLeft.Value, oRight.Value, iWeight);
}
else
{
sb.AppendFormat("{0}, {1} - ({2})", oLeft, oRight, iWeight);
}
}
else
{
sb.Append(iWeight);
}
}
return sb.ToString();
}
}
}
C#,哈夫曼编码(Huffman Code)压缩(Compress )与解压缩(Decompress)算法与源代码相关推荐
- 数据压缩之经典——哈夫曼编码(Huffman)
(笔记图片截图自课程Image and video processing: From Mars to Hollywood with a stop at the hospital的教学视频,使用时请注意 ...
- 哈夫曼编码与文件压缩
一:哈夫曼树与哈夫曼编码 大家知道,文件压缩的原理么? 假如我们有一个文件,文件当中仅有 A.B.C.D.E 五种字符,这五种字符出现的频率分别为 5次.4次.3次.2次.1次. 我们知道每个英文字母 ...
- 使用哈夫曼编码实现文件压缩__win10,c++
系统:win10 工具:vc6.0 //我加了个计时,用int存储字符总数 //因此增加一个限制:文件不可大于2GB #include<iostream> #include<time ...
- 数据结构C#版笔记--啥夫曼树(Huffman Tree)与啥夫曼编码(Huffman Encoding)
哈夫曼树Huffman tree 又称最优完全二叉树,切入正题之前,先看几个定义 1.路径 Path 简单点讲,路径就是从一个指定节点走到另一个指定节点所经过的分支,比如下图中的红色分支(A-> ...
- 贪心算法 - 哈夫曼编码 Huffman
转载地址 : http://blog.csdn.net/xuefeng0707/article/details/7844834 哈夫曼编码: 一种字符编码方式,常用于数据文件压缩.压缩率通常在2 ...
- 使用哈夫曼编码进行文件压缩
给你一个图片文件,要求对其进行无损压缩, 看看压缩效果如何. 思路:读取文件-> 得到赫夫曼编码表 -> 完成压缩 将前面压缩的文件,重新恢复成原来的文件. 思路:读取压缩文件(数据和赫夫 ...
- 霍夫曼树:霍夫曼编码(Huffman Tree:Huffman Coding)
一.简介 霍夫曼树常处理符号编写工作.根据整组数据中符号出现的频率高低,决定如何给符号编码.如果符号出现的频率越高,则给符号的码越短,相反符号的号码越长. 相关术语 路径:从书中一个节点到另一个节点之 ...
- 哈夫曼编码(Huffman)Java实现代码简化版
这个网上发现的Huffuman编码Java实现在组织上相对简化,便于理解文件压缩过程:提取文件统计字符频度-根据字符频度创建huffman树-根据huffman树生成huffman可变字长无前缀编码- ...
- 哈夫曼编码(Huffman)Java实现代码
网上找到的一个组Huffman编码Java实现代码,比较经典. 1.主类,压缩和解压 package cn.hm;import java.io.BufferedInputStream; import ...
- python哈夫曼编码注意_Python 算法(2) 哈夫曼编码 Huffman Encoding
这个问题原始是用来实现一个可变长度的编码问题,但可以总结成这样一个问题,假设我们有很多的叶子节点,每个节点都有一个权值w(可以是任何有意义的数值,比如它出现的概率),我们要用这些叶子节点构造一棵树,那 ...
最新文章
- jquery ready 与资源加载顺序
- 相关Linux命令的学习
- 服务器优化:Tomcat、JVM性能调优笔记
- 马哥linux第六周作业
- 简洁大气好看的个人博客模板HTML源码
- 明晚8点直播丨 Oracle RMAN 单实例异机迁移恢复(版本:11gR2)
- 未来计算机技术的发展趋势有哪些,计算机技术的未来发展趋势,以及其应用范围...
- python---之hasattr()
- Thrift搭建分布式微服务(四)
- 五子棋c语言开题报告,基于Java语言的五子棋游戏设计开题报告.doc
- 服务器运行时狂响,服务器常见故障大全
- 学习阿里代码规范笔记
- rancher拉取harbor私有镜像失败,报错ImagePullBackOff: Back-off pulling image
- pinctrl子系统初始化RGB灯
- 商城运费模板数据库简单设计思路
- VC 开机自动启动程序代码
- 求阶乘序列前N项和(15分)
- JAVA微信开发(四), 公众号普通红包
- The JAVA_HOME environment variable does not point to a working 32-bit JDK or JRE.
- 前端页面遇到稀有字体如何处理