LZ78编码

LZ78算法,建立词典的算法。

LZ78的编码思想:

不断地从字符流中提取新的缀-符串(String),通俗地理解为新"词条",然后用"代号"也就是码字(Code word)表示这个"词条"。

对字符流的编码就变成了用码字(Code word)去替换字符流(Charstream),生成码字流(Codestream),从而达到压缩数据的目的。

几个约定:

  1. 字符流(Charstream):要被编码的数据序列。
  2. 字符(Character):字符流中的基本数据单元。
  3. 前缀(Prefix): 在一个字符之前的字符序列。
  4. 缀-符串(String):前缀+字符。
  5. 码字(Code word):编码以后在码字流中的基本数据单元,代表词典中的一串字符
  6. 码字流(Codestream): 码字和字符组成的序列,是编码器的输出
  7. 词典(Dictionary): 缀-符串表。按照词典中的索引号对每条缀-符串(String)指定一个码字(Code word)
  8. 当前前缀(Current prefix):在编码算法中使用,指当前正在处理的前缀,用符号P表示
  9. 当前字符(Current character):在编码算法中使用,指当前前缀之后的字符,用符号Char表示。
  10. 当前码字(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#):

  1. /// <summary>
  2.     /// LZ78编码所需词典
  3.     /// </summary>
  4.     public struct Dictionary
  5.     {
  6.         public int id;
  7.         public string context;
  8.         public Dictionary(int id, string str)
  9.         {
  10.             this.id = id;
  11.             this.context = str;
  12.         }
  13.     }
  1. /// <summary>
  2.     /// 编码器类
  3.     /// </summary>
  4.     public static class Encoder
  5.     {
  6.         /// <summary>
  7.         /// 词典
  8.         /// </summary>
  9.         static List<Dictionary> D = new List<Dictionary>();
  10.  
  11.         /// <summary>
  12.         /// 在词典中查找相应串
  13.         /// </summary>
  14.         /// <param name="item"></param>
  15.         /// <param name="D"></param>
  16.         /// <returns></returns>
  17.         static bool Find(string item, List<Dictionary> D)
  18.         {
  19.             foreach (Dictionary d in D)
  20.                 if (d.context == item)
  21.                     return true;
  22.             return false;
  23.         }
  24.  
  25.         /// <summary>
  26.         /// 根据词典条目内容查找相应编号
  27.         /// </summary>
  28.         /// <param name="item"></param>
  29.         /// <param name="D"></param>
  30.         /// <returns></returns>
  31.         static int GetDicID(string item, List<Dictionary> D)
  32.         {
  33.             foreach (Dictionary d in D)
  34.                 if (d.context == item)
  35.                     return d.id;
  36.             return 0;
  37.         }
  38.  
  39.         /// <summary>
  40.         /// 将一个条目加入词典
  41.         /// </summary>
  42.         /// <param name="item"></param>
  43.         /// <param name="D"></param>
  44.         static void AddToDic(string item, List<Dictionary> D)
  45.         {
  46.             int maxID;
  47.             if (D.Count == 0)
  48.                 maxID = 0;
  49.             else
  50.                 maxID = D.Last().id;
  51.  
  52.             D.Add(new Dictionary(maxID + 1, item));
  53.         }
  54.  
  55.         /// <summary>
  56.         /// 显示词典
  57.         /// </summary>
  58.         public static void ShowDictionary()
  59.         {
  60.             Console.WriteLine("Dictionary:");
  61.             foreach (Dictionary d in D)
  62.             {
  63.                 Console.WriteLine("<{0},{1}>", d.id, d.context);
  64.             }
  65.         }
  66.  
  67.         /// <summary>
  68.         /// 执行LZ78编码算法
  69.         /// </summary>
  70.         /// <param name="str"></param>
  71.         public static void Execute(string str)
  72.         {
  73.             StringBuilder P = new StringBuilder();
  74.             char CHAR;
  75.             P.Clear();
  76.             foreach (char c in str)
  77.             {
  78.                 CHAR = c;
  79.                 if (Find((P.ToString() + CHAR.ToString()), D))
  80.                     P.Append(CHAR);
  81.                 else
  82.                 {
  83.                     Console.Write("({0},{1})", GetDicID(P.ToString(), D), c);
  84.                     AddToDic(P.ToString() + c.ToString(), D);
  85.                     P.Clear();
  86.                 }
  87.             }
  88.             if (P.ToString() != "")
  89.                 Console.Write("({0},{1})", GetDicID(P.ToString(), D), "/");
  90.             Console.WriteLine();
  91.         }
  92.     }
  1. /// <summary>
  2.     /// 解码器类
  3.     /// </summary>
  4.     public static class Decoder
  5.     {
  6.         /// <summary>
  7.         /// 内部类:将码字字符串转换为编码数组
  8.         /// </summary>
  9.         struct Codes
  10.         {
  11.             public int id;
  12.             public char code;
  13.             public Codes(int id, char code)
  14.             {
  15.                 this.id = id;
  16.                 this.code = code;
  17.             }
  18.         }
  19.  
  20.         /// <summary>
  21.         /// 词典
  22.         /// </summary>
  23.         static List<Dictionary> D = new List<Dictionary>();
  24.  
  25.         /// <summary>
  26.         /// 码字流,从字符串中获取
  27.         /// </summary>
  28.         static List<Codes> CodeStream = new List<Codes>();
  29.  
  30.         /// <summary>
  31.         /// 将码字串变为码字流
  32.         /// </summary>
  33.         /// <param name="str"></param>
  34.         static void BuildCodes(string str)
  35.         {
  36.             /******************
  37.              * stauts 定义:
  38.              * 0: 开始/结束状态
  39.              * 1: 逗号之前
  40.              * 2: 逗号之后
  41.              ******************/
  42.             int status = 0;
  43.             int id = 0;
  44.             char code = (char)0;
  45.             string number = "";
  46.             foreach (char c in str)
  47.             {
  48.                 if (c == '(')
  49.                     status = 1;
  50.  
  51.                 else if (status == 1 && c != ',')
  52.                     number += c;
  53.  
  54.                 else if (c == ',')
  55.                 {
  56.                     status = 2;
  57.                     id = Convert.ToInt32(number);
  58.                     number = "";
  59.                 }
  60.  
  61.                 else if (status == 2)
  62.                 {
  63.                     code = c;
  64.                     status = 0;
  65.                 }
  66.  
  67.                 else if (c == ')')
  68.                     CodeStream.Add(new Codes(id, code));
  69.             }
  70.         }
  71.  
  72.         /// <summary>
  73.         /// 将一个条目加入词典
  74.         /// </summary>
  75.         /// <param name="item"></param>
  76.         /// <param name="D"></param>
  77.         static void AddToDic(string item, List<Dictionary> D)
  78.         {
  79.             int maxID;
  80.             if (D.Count == 0)
  81.                 maxID = 0;
  82.             else
  83.                 maxID = D.Last().id;
  84.  
  85.             D.Add(new Dictionary(maxID + 1, item));
  86.         }
  87.  
  88.         /// <summary>
  89.         /// 根据词典序号找出词典内容
  90.         /// </summary>
  91.         /// <param name="id"></param>
  92.         /// <param name="D"></param>
  93.         /// <returns></returns>
  94.         static string GetContext(int id, List<Dictionary> D)
  95.         {
  96.             foreach (Dictionary d in D)
  97.             {
  98.                 if (d.id == id)
  99.                     return d.context;
  100.             }
  101.             return string.Empty;
  102.         }
  103.  
  104.         /// <summary>
  105.         /// 执行LZ78译码算法
  106.         /// </summary>
  107.         /// <param name="str"></param>
  108.         public static void Execute(string str)
  109.         {
  110.             int W;
  111.             char CHAR;
  112.             string original;
  113.  
  114.             BuildCodes(str);
  115.             foreach (Codes c in CodeStream)
  116.             {
  117.                 W = c.id;
  118.                 if (c.code != '/')
  119.                     CHAR = c.code;
  120.                 else CHAR = (char)0;
  121.                 if (W == 0)
  122.                 {
  123.                     Console.Write(CHAR);
  124.                     AddToDic(CHAR.ToString(), D);
  125.                 }
  126.                 else
  127.                 {
  128.                     original = GetContext(W, D);
  129.                     Console.Write(original + CHAR.ToString());
  130.                     AddToDic(original + CHAR.ToString(), D);
  131.                 }
  132.             }
  133.             Console.WriteLine();
  134.         }
  135.     }

执行效果(主界面程序代码省略):

可见算法执行的结果是完全正确的。

源码下载:http://files.cnblogs.com/ryuasuka/LZ78.rar

压缩算法实现之LZ78的更多相关文章

  1. ZIP压缩算法详细分析及解压实例解释

    最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...

  2. 【数据压缩】LZ78算法原理及实现

    在提出基于滑动窗口的LZ77算法后,两位大神Jacob Ziv与Abraham Lempel [1]于1978年又提出了LZ78算法:与LZ77算法不同的是LZ78算法使用树状词典维护历史字符串. [ ...

  3. 速度之王 — LZ4压缩算法(一)

    LZ4 (Extremely Fast Compression algorithm) 项目:http://code.google.com/p/lz4/ 作者:Yann Collet 本文作者:zhan ...

  4. 为什么倒排索引不采用zlib这样的字典压缩算法——因为没法直接使用啊

    看了下压缩算法的发展历史,根据倒排索引的数据结构特点,个人认为zstd不适合做倒排索引压缩,举例说明下: 假设有一份文档倒排列表为:[300, 302, 303, 332],对于这组倒排数据,是没法* ...

  5. LZ77压缩算法编码原理详解(结合图片和简单代码)

    前言 LZ77算法是无损压缩算法,由以色列人Abraham Lempel发表于1977年.LZ77是典型的基于字典的压缩算法,现在很多压缩技术都是基于LZ77.鉴于其在数据压缩领域的地位,本文将结合图 ...

  6. Java数据结构之对称矩阵的压缩算法---

    特殊矩阵 特殊矩阵是指这样一类矩阵,其中有许多值相同的元素或有许多零元素,且值相同的元素或零元素的分布有一定规律.一般采用二维数组来存储矩阵元素.但是,对于特殊矩阵,可以通过找出矩阵中所有值相同元素的 ...

  7. HBase中的压缩算法比较 GZIP、LZO、Zippy、Snappy [转]

    网址: http://www.cnblogs.com/panfeng412/archive/2012/12/24/applications-scenario-summary-of-compressio ...

  8. LZW压缩算法

    转载自http://www.cnblogs.com/jillzhang/archive/2006/11/06/551298.html 记录此处仅自己供学习之用 lzw解压缩算法: 用单个字符初始化字符 ...

  9. atitit.压缩算法 ZLib ,gzip ,zip 最佳实践 java .net php

    atitit.压缩算法 ZLib ,gzip ,zip   最佳实践  java .net php 1. 压缩算法的归类::: 纯算法,带归档算法 1 2. zlib(适合字符串压缩) 1 3. gz ...

随机推荐

  1. selenium验证车贷计算器算法

    1.验证页面上的车贷计算器算的结果是否与需求中给的公式结果一致. 页面图片: 代码如下(简单实现,需要优化): package com.test; import java.math.BigDecima ...

  2. [cocos2dx] 让UIButton支持disable状态

    摘要: 主要解决cocos2dx-2.2.2版本中, UIButton显示不了disable状态图的问题. 顺便, 理解了一下cocos2dx中UIWidget的渲染原理. 博客: http://ww ...

  3. nginx 一二事(2) - 创建虚拟静态服务器

    一.什么是nginx 是一个C语言开发的HTTP反向代理服务器,性能非常高 一个俄罗斯的哥们开发的,官方提供的测试性能能够达到5W的并发,我的天呐~,实际测试差不多是2W,而淘宝的牛人可以优化到200 ...

  4. Android开发配置,消除SDK更新时的“https://dl-ssl.google.com refused”异常

    消除SDK更新时的“https://dl-ssl.google.com refused”错误 消除SDK更新时,有可能会出现这样的错误:Download interrupted: hostname i ...

  5. Linux命令学习-mpstat

    mpstat 用于获取多个 CPU 相关统计信息的有用的命令是 mpstat.下面是一个示例输出: # mpstat -P ALL 5 2 Linux 2.6.9-67.ELsmp (oraclera ...

  6. 错误异常 (1)Android Studio错误提示:Gradle project sync failed. Basic functionality (eg. editing, debugging) will not work properly

    [已解决]Android Studio错误提示:Gradle project sync failed. Basic functionality (eg. editing, debugging) wil ...

  7. 准备写一些读书笔记,最近在填坑 SQL学习指南 Spring in Action effective Java

    把一些读书的理解通过白板图的形式展示出来,加深自己的认识, 因为目前没有工程项目练手,暂时在学习中把这些知识深化认识一下

  8. Redis集群环境的部署记录

    Redis Cluster终于出了Stable,这让人很是激动,等Stable很久了,所以还是先玩玩. 一. 集群简单概念. Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施( ...

  9. C# is as

    if(obj is ClassA) //遍历类层次,看OBJ是不是ClassA类型{    ClassA a=(ClassA) obj; //遍历类层次,看obj能否转换为ClassA,不成功则抛出异 ...

  10. ffplay 参数说明分享

    ffplay 使用参数说明分享 E:\SRCFORTEST\software\ffmpeg-20131021\ffmpeg-20131021-git-712eff4-win32-static\ bin ...