知道有的人比较懒,直接贴全部代码.
一开始一次性Code完了压缩部分代码.只调试了2,3次就成功了.
一次性写150行代码,没遇到什么bug的感觉还是蛮爽的.
写解压代码,才发现压缩代码有些细节问题.
对最后一个字符处理问题.
遇到比较折腾点:构建二叉树时,把原本应该是(叶结点的有值的)节点放在了左节点,正确应该放在右节点,导致生成的编码序列不满足(任意编码不是其他编码的前缀).导致解码失败.
使用方法:

var srcData = Encoding.UTF8.GetBytes(textBox1.Text);
            var cpsData = Compress(srcData);
            treeView1.ExpandAll();
           var depData = DeCompress(cpsData);
            var depStr = Encoding.UTF8.GetString(depData );

这个TreeView就是显示二叉树的,要添加控件,或者删除代码.

快速理解:
1.此压缩直接对字节流进行压缩.
2.压缩原理:字节流对每个直接使用率不平均,所以用变长的编码对256个字节重新编码,以较短的编码表示使用率高的字节,较长编码表示使用率低的字节.
所以总体来看,用新的编码表示的字节流要比原来的短.(除非字节流特别小,压缩效果就不好)
3.由于二叉树的性质,将使用率低的先加入树,使用率高的后加入作为使用率低的节点的父节点的兄弟节点(因为有值的节点必须是叶结点).从最底下向上构建
二叉树.
 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO; namespace 霍夫曼二叉树压缩
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var s=GetCode();
var b= GetByteByCode(s);
} private void button1_Click(object sender, EventArgs e)
{
var srcData = Encoding.UTF8.GetBytes(textBox1.Text);
var cpsData = Compress(srcData);
treeView1.ExpandAll();
var depData = DeCompress(cpsData);
var depStr = Encoding.UTF8.GetString(depData );
} Dictionary<int, string> dicCode = new Dictionary<int, string>();
byte[] Compress(byte[] data)
{
Dictionary<byte, int> everyCount = new Dictionary<byte, int>();
foreach (var d in data)
{
if(everyCount.ContainsKey(d)==false )
everyCount.Add(d,);
everyCount[d]++;
}
var orderAscCounts = everyCount.OrderBy(a=>a.Value);
Queue<Count> queCouts = new Queue<Count>();
orderAscCounts.ToList().ForEach(d => {
queCouts.Enqueue(new Count { key=d.Key, count=d.Value });
});
BuildTree(ref queCouts);
foreach (var a in BNode.nodes)
{
var code = new string(GetCode(a).Reverse().ToArray());
dicCode.Add(a.key,code);
}
BNode root = BNode.nodes[];
while(root.parent!=null){
root = root.parent;
}
CreateTreeView(root,treeView1.Nodes);
string curCode = "";
List<byte> outData = new List<byte>();
foreach (var d in data)
{
curCode += dicCode[d];
if (curCode.Length >= )
{
byte curBit = GetByteByCode(curCode.Substring(,));
outData.Add(curBit);
curCode = curCode.Length > ? curCode.Substring(, curCode.Length - ) : "";
}
}
if (curCode != "")
{
curCode = curCode.PadRight(,'');
byte curBit = GetByteByCode(curCode);
outData.Add(curBit);
} return outData.ToArray();
} byte[] DeCompress(byte[] data)
{
string codes = "";
for (int i = ; i < data.Length - ;i++ )
{
codes += GetCode(data[i]);
}
codes += GetCode(data[data.Length-]).TrimEnd('');
var bdata = GetCode(codes); return bdata;
} byte GetByteByCode(string curCode)
{
return Convert.ToByte(curCode, );
}
byte[] GetCode(string code)
{
List<byte> datas = new List<byte>();
int pos = ;
var orderDicCode=dicCode.OrderByDescending(a=>a.Value.Length);
do{
int p=-;
foreach (var vCode in orderDicCode)
{
p = code.IndexOf(vCode.Value);
if (p == )
{
datas.Add((byte)vCode.Key);
code = code.Substring(vCode.Value.Length , code.Length-vCode.Value.Length );
break;
}
}
if (p == -)
{
throw new Exception("解压出错:发现未能识别的编码,编码表或数据已被破坏!");
}
}while(code.Length>); /* for (int i = 1; pos + i < code.Length ; i++)
{
var firstCode = code.Substring(pos, i);
var secondCode = code.Substring(pos, i + 1); var first = dicCode.Where(a => a.Value == firstCode);
var second = dicCode.Where(a => a.Value == secondCode);
if (first.Count() > 0 && second.Count() == 0 ){
datas.Add( (byte)first.First().Key);
pos = pos+i;
i = 1;
} else if (pos + i == code.Length - 1 && second.Count() > 0)
datas.Add( (byte)second.First().Key );
}*/
return datas.ToArray();
}
string GetCode(byte b )
{
return Convert.ToString(b, ).PadLeft(, '');//Convert.ToString(b, 2) ;//:
}
string GetCode(BNode a)
{
if (a.parent!=null)
return (a.isLeft ? "" : "")+GetCode(a.parent);
return "" ;
} BNode BuildTree(ref Queue<Count> queCouts )
{
var first = queCouts.Dequeue();
var second = queCouts.Dequeue(); var lft =first.node==null? new BNode { key=first.key, count=first.count } : first.node; var rgt = second.node == null ? new BNode { key = second.key, count = second.count } : second.node; if (rgt.key == -)
{
var temp = lft;
lft = rgt;
rgt = temp; } var pnode = new BNode
{
key = -, count = first.count + second.count
};
lft.isLeft = true;
rgt.isLeft = false;
pnode.left = lft;
pnode.right = rgt;
lft.parent = pnode; rgt.parent = pnode;
if (lft.key != -)
BNode.nodes.Add(lft);
if (rgt.key != -)
BNode.nodes.Add(rgt);
if (queCouts.Count > ){
queCouts.Enqueue(new Count { count=pnode.count, key=pnode.key, node=pnode });
var orderQue = queCouts.OrderBy(q => q.count).ToList();
queCouts.Clear();
foreach (var a in orderQue)
queCouts.Enqueue(a);
return BuildTree(ref queCouts);
}
else
return pnode;
} void CreateTreeView(BNode node , TreeNodeCollection tnc)
{
if (node == null) return;
var newNode = tnc.Add((node.isLeft ? "" : "") + (node.key!=-?"-"+node.key + ":" + node.count:""));
CreateTreeView(node.left,newNode.Nodes);
CreateTreeView(node.right, newNode.Nodes);
} class Count
{
public int key;
public int count;
public BNode node;
} class BNode{
public int key;
public int count;
public BNode left;
public BNode right;
public BNode parent;
public bool isLeft = false;
public static List<BNode> nodes = new List< BNode>(); }
}
}

C# 霍夫曼二叉树压缩算法实现的更多相关文章

  1. 赫夫曼\哈夫曼\霍夫曼编码 (Huffman Tree)

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

  2. word2vec 中的数学原理二 预备知识 霍夫曼树

    主要参考:    word2vec 中的数学原理详解                 自己动手写 word2vec 编码的话,根是不记录在编码中的 这一篇主要讲的就是霍夫曼树(最优二叉树)和编码.  ...

  3. 霍夫曼编码(Huffman Coding)

    霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种. 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符 ...

  4. CF 463A && 463B 贪心 && 463C 霍夫曼树 && 463D 树形dp && 463E 线段树

    http://codeforces.com/contest/462 A:Appleman and Easy Task 要求是否全部的字符都挨着偶数个'o' #include <cstdio> ...

  5. word2vec中关于霍夫曼树的

    再谈word2vec 标签: word2vec自然语言处理NLP深度学习语言模型 2014-05-28 17:17 16937人阅读 评论(7) 收藏 举报  分类: Felven在职场(86)    ...

  6. Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树

    Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 目录 Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 0x00 摘要 0x01 背景概念 1.1 词向量基础 ...

  7. Java数据结构(十二)—— 霍夫曼树及霍夫曼编码

    霍夫曼树 基本介绍和创建 基本介绍 又称哈夫曼树,赫夫曼树 给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称为最优二叉树 霍夫曼树是带权路径长度最短的树,权值较 ...

  8. 基于python的二元霍夫曼编码译码详细设计

    一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图 ...

  9. 采用霍夫曼编码(Huffman)画出字符串各字符编码的过程并求出各字符编码 --多媒体技术与应用

    题目:有一个字符串:cabcedeacacdeddaaaba,问题: (1)采用霍夫曼编码画出编码的过程,并写出各字符的编码 (2)根据求得的编码,求得各编码需要的总位数 (3)求出整个字符串总编码长 ...

随机推荐

  1. java + spring (jython\python\script) Error:SyntaxError: no viable alternative at character '\n'

    使用Jython结合java和Python开发功能时,要是遇到如下情况: 2016-03-10 16:16:49 DEBUG [com.freedom.orion.configs.JyhtonConf ...

  2. hOAuth2.0认证和授权原理

    原文地址: http://www.6zou.net/tech/what_is_oauth.html http://www.phpddt.com/%E4%BA%8C%E6%AC%A1%E5%BC%80% ...

  3. mysql之索引方面的知识点总结

    索引的类型: 普通索引:这是最基本的索引类型,没唯一性之类的限制. 唯一性索引:和普通索引基本相同,但所有的索引列只能出现一次,保持唯一性. 主键:主键是一种唯一索引,但必须指定为"PRIM ...

  4. Mysql 8个小时连接断开问题解析

    wait_timeout — 指的是mysql在关闭一个非交互的连接之前所要等待的秒数,其取值范围为1-2147483(Windows),1-31536000(linux),默认值28800. int ...

  5. 14.7.4 InnoDB File-Per-Table Tablespaces

    14.7.4 InnoDB File-Per-Table Tablespaces 从历史上看,所有的InnoDB 表和indexes 是存储在system 表空间. 这个整体的方法是针对机器是整个用于 ...

  6. 14.6.3.5 Configuring InnoDB Buffer Pool Flushing

    14.6.3.5 Configuring InnoDB Buffer Pool Flushing InnoDB 执行某些任务在后台, 包括脏叶的刷新(那些已经发生改变的pages 但是没有写入到数据文 ...

  7. Android MonkeyRunner自动拨打电话

    from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice import time device = MonkeyRunner.wa ...

  8. C#编程技术层次

    不谈具体领域(比如搜索,视频,网络等),单就编程语言这个垂直方向,大体上对它有一个如下的层次划分. 1. 基本运用C#语法,在各种工具和示例代码的支持下,完成一些基本程序任务 2. 熟练掌握面向对象与 ...

  9. Linux学习笔记15——GDB 命令详细解释【转】

    GDB 命令详细解释 Linux中包含有一个很有用的调试工具--gdb(GNU Debuger),它可以用来调试C和C++程序,功能不亚于Windows下的许多图形界面的调试工具. 和所有常用的调试工 ...

  10. php 下载

    $file='url.xlsx'; if (file_exists(EA_DIR_DATA . $file)) {            header('Content-Description: Fi ...