C# 霍夫曼二叉树压缩算法实现
知道有的人比较懒,直接贴全部代码.
一开始一次性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# 霍夫曼二叉树压缩算法实现的更多相关文章
- 赫夫曼\哈夫曼\霍夫曼编码 (Huffman Tree)
哈夫曼树 给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离 ...
- word2vec 中的数学原理二 预备知识 霍夫曼树
主要参考: word2vec 中的数学原理详解 自己动手写 word2vec 编码的话,根是不记录在编码中的 这一篇主要讲的就是霍夫曼树(最优二叉树)和编码. ...
- 霍夫曼编码(Huffman Coding)
霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种. 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符 ...
- CF 463A && 463B 贪心 && 463C 霍夫曼树 && 463D 树形dp && 463E 线段树
http://codeforces.com/contest/462 A:Appleman and Easy Task 要求是否全部的字符都挨着偶数个'o' #include <cstdio> ...
- word2vec中关于霍夫曼树的
再谈word2vec 标签: word2vec自然语言处理NLP深度学习语言模型 2014-05-28 17:17 16937人阅读 评论(7) 收藏 举报 分类: Felven在职场(86) ...
- Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树
Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 目录 Alink漫谈(十六) :Word2Vec源码分析 之 建立霍夫曼树 0x00 摘要 0x01 背景概念 1.1 词向量基础 ...
- Java数据结构(十二)—— 霍夫曼树及霍夫曼编码
霍夫曼树 基本介绍和创建 基本介绍 又称哈夫曼树,赫夫曼树 给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称为最优二叉树 霍夫曼树是带权路径长度最短的树,权值较 ...
- 基于python的二元霍夫曼编码译码详细设计
一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图 ...
- 采用霍夫曼编码(Huffman)画出字符串各字符编码的过程并求出各字符编码 --多媒体技术与应用
题目:有一个字符串:cabcedeacacdeddaaaba,问题: (1)采用霍夫曼编码画出编码的过程,并写出各字符的编码 (2)根据求得的编码,求得各编码需要的总位数 (3)求出整个字符串总编码长 ...
随机推荐
- [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】
题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...
- leetcode面试准备: Jump Game
1 题目 Given an array of non-negative integers, you are initially positioned at the first index of the ...
- gitweb安装
gitweb安装: 1. 简介 Gitweb提供了git版本库的图形化web浏览功能.可以到网站http://git.kernel.org/体验下效果,如下图所示. Gitweb界面 它既可以通过配置 ...
- 【转】Android--多线程之Handler--不错
原文网址:http://www.cnblogs.com/plokmju/p/android_handler.html 前言 Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了 ...
- JavaScript高级程序设计7.pdf
function类型 每个函数都是function类型的实例,函数是对象,函数名是指向对象的指针 function sum(num1,num2) { return num1+num2; } //等价于 ...
- SRM 440(1-250pt, 1-500pt)
DIV1 250pt 题意:小球从一段折线斜坡上滚下来,告诉所用时间,求重力加速度. 解法:二分答案模拟即可. tag:二分,simulation // BEGIN CUT HERE /* * Aut ...
- hdoj 1686 Oulipo【求一个字符串在另一个字符串中出现次数】
Oulipo Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- ios socket通讯注意事项
前段时间,在做objetive-c下的Sokcet通讯,当使用C++程序做服务端时,一切正常;当用JAVA做服务端时,双方收不到数据,在查阅了一些资料后,整理一下注意点 1 消息末尾加回车和换行符 o ...
- mac svn命令
转载:Mac下svn command命令 svn help command 获取子命令说明 svn info $URL 查看工作空间信息 svn list 显示当前目录下svn记录文件列表,不访 ...
- 使用Spring-data-redis操作Redis的Sentinel
介绍 Spring-Data-Redis项目(简称SDR) 是对Redis的Key-Value数据存储操作提供了更高层次的抽象,提供了一个对几种主要的redis的Java客户端(例 如:jedis,j ...