知道有的人比较懒,直接贴全部代码.
一开始一次性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. iPhone开发 - 常用库

    iPhone开发 - 常用库 这里总结了iPhone开发者开发过程中可能需要的一些资源 如何用Facebook graphic api上传视频: http://developers.facebook. ...

  2. 安卓天天练练(三)常用组件Toast

    要写几句java package com.narumi.android_7_2; import android.app.Activity; import android.os.Bundle; impo ...

  3. C# 读写INI 文件

    INI 格式: [Section1] KeyWord1 = Value1 KeyWord2 = Value2 ... [Section2] KeyWord3 = Value3 KeyWord4 = V ...

  4. 【HDOJ】2782 The Worm Turns

    DFS. /* 2782 */ #include <iostream> #include <queue> #include <cstdio> #include &l ...

  5. 【POJ】1451 T9

    DFS+字典树. #include <cstdio> #include <cstring> #include <cstdlib> typedef struct Tr ...

  6. Kafka Topic Partition Replica Assignment实现原理及资源隔离方案

    本文共分为三个部分:   Kafka Topic创建方式 Kafka Topic Partitions Assignment实现原理 Kafka资源隔离方案   1. Kafka Topic创建方式 ...

  7. HDU 5933 ArcSoft's Office Rearrangement 【模拟】(2016年中国大学生程序设计竞赛(杭州))

    ArcSoft's Office Rearrangement Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  8. 【狼】unity3d iTween插件的学习

    之前在一个三消游戏项目中接触到iTween,最近又要用到,发现iTween真的是一个很好用,省事的插件,有很多函数里包括 Hashtable的他都用一个函数很简单的完成了, 举几个例子 void Lo ...

  9. SWMM代码移植到64位平台

    在32位平台上运行SWMM模型,当节点数量到达60万以上的时候,模型运行占用内存接近1.85G的时候就会因为内存不够而无法计算.这种情况还是单独运行SWMM.exe的时候出现,如果采用SWMM.DLL ...

  10. poj 1696 Space Ant 极角排序

    #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #inclu ...