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)算法与源代码相关推荐

  1. 数据压缩之经典——哈夫曼编码(Huffman)

    (笔记图片截图自课程Image and video processing: From Mars to Hollywood with a stop at the hospital的教学视频,使用时请注意 ...

  2. 哈夫曼编码与文件压缩

    一:哈夫曼树与哈夫曼编码 大家知道,文件压缩的原理么? 假如我们有一个文件,文件当中仅有 A.B.C.D.E 五种字符,这五种字符出现的频率分别为 5次.4次.3次.2次.1次. 我们知道每个英文字母 ...

  3. 使用哈夫曼编码实现文件压缩__win10,c++

    系统:win10 工具:vc6.0 //我加了个计时,用int存储字符总数 //因此增加一个限制:文件不可大于2GB #include<iostream> #include<time ...

  4. 数据结构C#版笔记--啥夫曼树(Huffman Tree)与啥夫曼编码(Huffman Encoding)

    哈夫曼树Huffman tree 又称最优完全二叉树,切入正题之前,先看几个定义 1.路径 Path 简单点讲,路径就是从一个指定节点走到另一个指定节点所经过的分支,比如下图中的红色分支(A-> ...

  5. 贪心算法 - 哈夫曼编码 Huffman

    转载地址  :   http://blog.csdn.net/xuefeng0707/article/details/7844834 哈夫曼编码: 一种字符编码方式,常用于数据文件压缩.压缩率通常在2 ...

  6. 使用哈夫曼编码进行文件压缩

    给你一个图片文件,要求对其进行无损压缩, 看看压缩效果如何. 思路:读取文件-> 得到赫夫曼编码表 -> 完成压缩 将前面压缩的文件,重新恢复成原来的文件. 思路:读取压缩文件(数据和赫夫 ...

  7. 霍夫曼树:霍夫曼编码(Huffman Tree:Huffman Coding)

    一.简介 霍夫曼树常处理符号编写工作.根据整组数据中符号出现的频率高低,决定如何给符号编码.如果符号出现的频率越高,则给符号的码越短,相反符号的号码越长. 相关术语 路径:从书中一个节点到另一个节点之 ...

  8. 哈夫曼编码(Huffman)Java实现代码简化版

    这个网上发现的Huffuman编码Java实现在组织上相对简化,便于理解文件压缩过程:提取文件统计字符频度-根据字符频度创建huffman树-根据huffman树生成huffman可变字长无前缀编码- ...

  9. 哈夫曼编码(Huffman)Java实现代码

    网上找到的一个组Huffman编码Java实现代码,比较经典. 1.主类,压缩和解压 package cn.hm;import java.io.BufferedInputStream; import ...

  10. python哈夫曼编码注意_Python 算法(2) 哈夫曼编码 Huffman Encoding

    这个问题原始是用来实现一个可变长度的编码问题,但可以总结成这样一个问题,假设我们有很多的叶子节点,每个节点都有一个权值w(可以是任何有意义的数值,比如它出现的概率),我们要用这些叶子节点构造一棵树,那 ...

最新文章

  1. jquery ready 与资源加载顺序
  2. 相关Linux命令的学习
  3. 服务器优化:Tomcat、JVM性能调优笔记
  4. 马哥linux第六周作业
  5. 简洁大气好看的个人博客模板HTML源码
  6. 明晚8点直播丨 Oracle RMAN 单实例异机迁移恢复(版本:11gR2)
  7. 未来计算机技术的发展趋势有哪些,计算机技术的未来发展趋势,以及其应用范围...
  8. python---之hasattr()
  9. Thrift搭建分布式微服务(四)
  10. 五子棋c语言开题报告,基于Java语言的五子棋游戏设计开题报告.doc
  11. 服务器运行时狂响,服务器常见故障大全
  12. 学习阿里代码规范笔记
  13. rancher拉取harbor私有镜像失败,报错ImagePullBackOff: Back-off pulling image
  14. pinctrl子系统初始化RGB灯
  15. 商城运费模板数据库简单设计思路
  16. VC 开机自动启动程序代码
  17. 求阶乘序列前N项和(15分)
  18. JAVA微信开发(四), 公众号普通红包
  19. The JAVA_HOME environment variable does not point to a working 32-bit JDK or JRE.
  20. 前端页面遇到稀有字体如何处理

热门文章

  1. A B 表的设计思路
  2. 如何安装博通 BCM43142 网卡驱动
  3. python小练习——歌词解析
  4. cf服务器维护时能否更新游戏,CF新版本今日更新维护公告
  5. Maemo 中交叉编译D-BUS 1.2.1
  6. Pandas合并DataFrame数据写入Excels
  7. 嵌入式开发:安全嵌入式系统的5个要素—第5部分:安全存储
  8. 解决Github上下载项目失败或速度太慢的问题
  9. HyperLPR3车牌识别-五分钟搞定: 中文车牌识别光速部署与使用
  10. python3爬虫系列24之重庆微博地铁客运量爬取且可视化输出