压缩算法实现之LZ78
LZ78编码
LZ78算法,建立词典的算法。
LZ78的编码思想:
不断地从字符流中提取新的缀-符串(String),通俗地理解为新"词条",然后用"代号"也就是码字(Code word)表示这个"词条"。
对字符流的编码就变成了用码字(Code word)去替换字符流(Charstream),生成码字流(Codestream),从而达到压缩数据的目的。
几个约定:
- 字符流(Charstream):要被编码的数据序列。
- 字符(Character):字符流中的基本数据单元。
- 前缀(Prefix): 在一个字符之前的字符序列。
- 缀-符串(String):前缀+字符。
- 码字(Code word):编码以后在码字流中的基本数据单元,代表词典中的一串字符
- 码字流(Codestream): 码字和字符组成的序列,是编码器的输出
- 词典(Dictionary): 缀-符串表。按照词典中的索引号对每条缀-符串(String)指定一个码字(Code word)
- 当前前缀(Current prefix):在编码算法中使用,指当前正在处理的前缀,用符号P表示
- 当前字符(Current character):在编码算法中使用,指当前前缀之后的字符,用符号Char表示。
- 当前码字(Current code word): 在译码算法中使用,指当前处理的码字,用W表示当前码字,String.W表示当前码字的缀-符串。
编码算法步骤:
步骤1: 在开始时,词典和当前前缀P 都是空的。
步骤2: 当前字符Char :=字符流中的下一个字符。
步骤3: 判断P+Char是否在词典中:
(1) 如果"是":用Char扩展P,让P := P+Char ;
(2) 如果"否":① 输出与当前前缀P相对应的码字和当前字符Char;
② 把字符串P+Char 添加到词典中。③ 令P :=空值。
(3) 判断字符流中是否还有字符需要编码
① 如果"是":返回到步骤2。
② 如果"否":若当前前缀P不空,输出相应于当前前缀P的码字,结束编码。
解码算法步骤:
步骤1:在开始时词典为空;
步骤2:当前码字W:= 码字流中的下一个码字
步骤3:当前字符Char:=紧随码字之后的字符
步骤4:把当前码字的缀-符串(string.W)输出到字符流,然后输出字符Char
步骤5:把string.W + Char添加到词典中
步骤6:判断码字流中是否还有码字要译码,
(1)如果有,返回步骤2 (2)如果没有,则结束
代码实现(C#):
- /// <summary>
- /// LZ78编码所需词典
- /// </summary>
- public struct Dictionary
- {
- public int id;
- public string context;
- public Dictionary(int id, string str)
- {
- this.id = id;
- this.context = str;
- }
- }
- /// <summary>
- /// 编码器类
- /// </summary>
- public static class Encoder
- {
- /// <summary>
- /// 词典
- /// </summary>
- static List<Dictionary> D = new List<Dictionary>();
- /// <summary>
- /// 在词典中查找相应串
- /// </summary>
- /// <param name="item"></param>
- /// <param name="D"></param>
- /// <returns></returns>
- static bool Find(string item, List<Dictionary> D)
- {
- foreach (Dictionary d in D)
- if (d.context == item)
- return true;
- return false;
- }
- /// <summary>
- /// 根据词典条目内容查找相应编号
- /// </summary>
- /// <param name="item"></param>
- /// <param name="D"></param>
- /// <returns></returns>
- static int GetDicID(string item, List<Dictionary> D)
- {
- foreach (Dictionary d in D)
- if (d.context == item)
- return d.id;
- return 0;
- }
- /// <summary>
- /// 将一个条目加入词典
- /// </summary>
- /// <param name="item"></param>
- /// <param name="D"></param>
- static void AddToDic(string item, List<Dictionary> D)
- {
- int maxID;
- if (D.Count == 0)
- maxID = 0;
- else
- maxID = D.Last().id;
- D.Add(new Dictionary(maxID + 1, item));
- }
- /// <summary>
- /// 显示词典
- /// </summary>
- public static void ShowDictionary()
- {
- Console.WriteLine("Dictionary:");
- foreach (Dictionary d in D)
- {
- Console.WriteLine("<{0},{1}>", d.id, d.context);
- }
- }
- /// <summary>
- /// 执行LZ78编码算法
- /// </summary>
- /// <param name="str"></param>
- public static void Execute(string str)
- {
- StringBuilder P = new StringBuilder();
- char CHAR;
- P.Clear();
- foreach (char c in str)
- {
- CHAR = c;
- if (Find((P.ToString() + CHAR.ToString()), D))
- P.Append(CHAR);
- else
- {
- Console.Write("({0},{1})", GetDicID(P.ToString(), D), c);
- AddToDic(P.ToString() + c.ToString(), D);
- P.Clear();
- }
- }
- if (P.ToString() != "")
- Console.Write("({0},{1})", GetDicID(P.ToString(), D), "/");
- Console.WriteLine();
- }
- }
- /// <summary>
- /// 解码器类
- /// </summary>
- public static class Decoder
- {
- /// <summary>
- /// 内部类:将码字字符串转换为编码数组
- /// </summary>
- struct Codes
- {
- public int id;
- public char code;
- public Codes(int id, char code)
- {
- this.id = id;
- this.code = code;
- }
- }
- /// <summary>
- /// 词典
- /// </summary>
- static List<Dictionary> D = new List<Dictionary>();
- /// <summary>
- /// 码字流,从字符串中获取
- /// </summary>
- static List<Codes> CodeStream = new List<Codes>();
- /// <summary>
- /// 将码字串变为码字流
- /// </summary>
- /// <param name="str"></param>
- static void BuildCodes(string str)
- {
- /******************
- * stauts 定义:
- * 0: 开始/结束状态
- * 1: 逗号之前
- * 2: 逗号之后
- ******************/
- int status = 0;
- int id = 0;
- char code = (char)0;
- string number = "";
- foreach (char c in str)
- {
- if (c == '(')
- status = 1;
- else if (status == 1 && c != ',')
- number += c;
- else if (c == ',')
- {
- status = 2;
- id = Convert.ToInt32(number);
- number = "";
- }
- else if (status == 2)
- {
- code = c;
- status = 0;
- }
- else if (c == ')')
- CodeStream.Add(new Codes(id, code));
- }
- }
- /// <summary>
- /// 将一个条目加入词典
- /// </summary>
- /// <param name="item"></param>
- /// <param name="D"></param>
- static void AddToDic(string item, List<Dictionary> D)
- {
- int maxID;
- if (D.Count == 0)
- maxID = 0;
- else
- maxID = D.Last().id;
- D.Add(new Dictionary(maxID + 1, item));
- }
- /// <summary>
- /// 根据词典序号找出词典内容
- /// </summary>
- /// <param name="id"></param>
- /// <param name="D"></param>
- /// <returns></returns>
- static string GetContext(int id, List<Dictionary> D)
- {
- foreach (Dictionary d in D)
- {
- if (d.id == id)
- return d.context;
- }
- return string.Empty;
- }
- /// <summary>
- /// 执行LZ78译码算法
- /// </summary>
- /// <param name="str"></param>
- public static void Execute(string str)
- {
- int W;
- char CHAR;
- string original;
- BuildCodes(str);
- foreach (Codes c in CodeStream)
- {
- W = c.id;
- if (c.code != '/')
- CHAR = c.code;
- else CHAR = (char)0;
- if (W == 0)
- {
- Console.Write(CHAR);
- AddToDic(CHAR.ToString(), D);
- }
- else
- {
- original = GetContext(W, D);
- Console.Write(original + CHAR.ToString());
- AddToDic(original + CHAR.ToString(), D);
- }
- }
- Console.WriteLine();
- }
- }
执行效果(主界面程序代码省略):

可见算法执行的结果是完全正确的。
源码下载:http://files.cnblogs.com/ryuasuka/LZ78.rar
压缩算法实现之LZ78的更多相关文章
- ZIP压缩算法详细分析及解压实例解释
最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...
- 【数据压缩】LZ78算法原理及实现
在提出基于滑动窗口的LZ77算法后,两位大神Jacob Ziv与Abraham Lempel [1]于1978年又提出了LZ78算法:与LZ77算法不同的是LZ78算法使用树状词典维护历史字符串. [ ...
- 速度之王 — LZ4压缩算法(一)
LZ4 (Extremely Fast Compression algorithm) 项目:http://code.google.com/p/lz4/ 作者:Yann Collet 本文作者:zhan ...
- 为什么倒排索引不采用zlib这样的字典压缩算法——因为没法直接使用啊
看了下压缩算法的发展历史,根据倒排索引的数据结构特点,个人认为zstd不适合做倒排索引压缩,举例说明下: 假设有一份文档倒排列表为:[300, 302, 303, 332],对于这组倒排数据,是没法* ...
- LZ77压缩算法编码原理详解(结合图片和简单代码)
前言 LZ77算法是无损压缩算法,由以色列人Abraham Lempel发表于1977年.LZ77是典型的基于字典的压缩算法,现在很多压缩技术都是基于LZ77.鉴于其在数据压缩领域的地位,本文将结合图 ...
- Java数据结构之对称矩阵的压缩算法---
特殊矩阵 特殊矩阵是指这样一类矩阵,其中有许多值相同的元素或有许多零元素,且值相同的元素或零元素的分布有一定规律.一般采用二维数组来存储矩阵元素.但是,对于特殊矩阵,可以通过找出矩阵中所有值相同元素的 ...
- HBase中的压缩算法比较 GZIP、LZO、Zippy、Snappy [转]
网址: http://www.cnblogs.com/panfeng412/archive/2012/12/24/applications-scenario-summary-of-compressio ...
- LZW压缩算法
转载自http://www.cnblogs.com/jillzhang/archive/2006/11/06/551298.html 记录此处仅自己供学习之用 lzw解压缩算法: 用单个字符初始化字符 ...
- atitit.压缩算法 ZLib ,gzip ,zip 最佳实践 java .net php
atitit.压缩算法 ZLib ,gzip ,zip 最佳实践 java .net php 1. 压缩算法的归类::: 纯算法,带归档算法 1 2. zlib(适合字符串压缩) 1 3. gz ...
随机推荐
- HDU 5056 Boring Count --统计
题解见官方题解,我这里只实现一下,其实官方题解好像有一点问题诶,比如 while( str[startPos] != str[i+1] ) cnt[str[startPos]]--, startPos ...
- POJ 3264 Balanced Lineup -- RMQ或线段树
一段区间的最值问题,用线段树或RMQ皆可.两种代码都贴上:又是空间换时间.. RMQ 解法:(8168KB 1625ms) #include <iostream> #include < ...
- ios之申请后台延时执行和做一个假后台的方法(系统进入长时间后台后,再进入前台部分功能不能实现)
转自:http://sis hu ok.com/forum/blogCategory/showByCategory.html?categories_id=138&user_id=10385 ...
- Git技巧总结分享
接触Git有很长一段时间了,从最初的不懂到逐渐熟悉运用,相比于SVN,更热衷于Git这一款强大的版本控制工具. 废话不多说,下面对Git做了一些技巧总结,在此分享下,希望能帮助到一些喜欢Git的朋友们 ...
- EasyUI概述
EasyUI是基于jQuery的一套UI框架,主要应用场景是后台管理系统的UI开发. 其提供了以下几个模块的插件 1.布局 2.菜单与按钮 3.表单 4.窗口 可以让开发人员,特别是后端开发人员,在不 ...
- Microsoft Visual Studio 下载转帖
1.VS2010 2.VS2012 Visual Studio 2012 Ultimate旗舰版序列号: YKCW6-BPFPF-BT8C9-7DCTH-QXGWC YQ7PR-QTHDM-HCBCV ...
- es安装
1,安装java(至少1.8) yum install -y java java -version 在/etc/profile追加: JAVA_HOME=/usr/java/jdk1..0_45 PA ...
- Linux Linux程序练习八
题目:自己动手实现一个守护进程,当控制台窗口关闭时还可以在后台运行.每隔一秒钟向my.log文件中插入一条记录,记录格式如下:yyyy-mm-dd hh:mi:se 记录内容,其中yyyy为年,mm为 ...
- .net面试题(.Net+Html+Javascript)
.net方面 1.简述 private. protected. public. internal 修饰符的访问权限. 2.override与重载的区别 3..net值类型和引用类型的区别,写出代码样例 ...
- JS案例之7——瀑布流布局(2)
这个例子与上一篇类似,唯一的区别是排序的方式有差别.上一篇是在高度最小的列里插入内容,这个案例是按顺序放置内容. 两种方法各有优缺点.第一种需要在图片内容加载完成的情况下有效.这个例子不需要在wind ...