zoukankan      html  css  js  c++  java
  • 压缩算法实现之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

     
     
    分类: .NET随笔
  • 相关阅读:
    关于<form:select>
    关于AJAX
    关于Listener
    分页显示数据----前端(将数据库中的信息分页显示到网页)
    分页显示数据----后台(将数据库中的信息分页显示到网页)
    关于Filter
    Myeclise下tomcat启动报错,启动超时
    启动tomcat一闪而过问题调试并解决
    MyEclipse快捷键大全【转】
    JSON和JS对象之间的互转【转】
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3149119.html
Copyright © 2011-2022 走看看