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. 边工作边刷题:70天一遍leetcode: day 75-2

    Strobogrammatic Number I/II/III 要点:记题,注意轴对称和点对称的区别.这题就是几个固定digit之间的palindrome I https://repl.it/CqLu ...

  2. 边工作边刷题:70天一遍leetcode: day 82

    Closest Binary Search Tree Value 要点: https://repl.it/CfhL/1 # Definition for a binary tree node. # c ...

  3. HOJ 1640 Mobile Phone

    题意:有一个n*n的矩阵,op==1时,在(x,y)增加值z,op==2时,求以(x1,y1)和(x2,y2)构成的矩阵的和. 思路:二维线段树. 代码: #include<stdio.h> ...

  4. GitHub Top 100的Android开源库

    摘要: 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索Java语言选择「Best M... 本项目主要对目前 GitH ...

  5. 仙人掌(cactus)

    仙人掌(cactus) Time Limit:1000ms Memory Limit:64MB 题目描述 LYK 在冲刺清华集训(THUSC) !于是它开始研究仙人掌,它想来和你一起分享它最近研究的 ...

  6. eclipse android 不会自动生成R.java文件和包的解决办法

    eclipse下编写android程序突然不会自动生成R.java文件和包的解决办法   我的eclipse原来是好好的,什么问题都没有的,结果今天一打开新建一个android程序,发现工程里不会自动 ...

  7. c# 调用打印机

    1.本地打印机 //添加引用并using System.Management; public static void AvailablePrinters() { ManagementScope ms ...

  8. Node.js开发环境搭建

    1.安装express npm install express -g 2.express33.6以后把express-generator分离出来了,所以还需安装express-generator,否则 ...

  9. WCF 异步调用问题

    添加引用时生成"勾选允许生成异步操作" Wcf异步调用三种方式: 第一种:直接调用异步方法 var serviceClient = new MyServiceClient(); s ...

  10. hp_jetdirect 9100漏洞检测

    #-*-coding=utf8-*- import socket import sys def main(): if len(sys.argv)<=1: print('Parameters er ...