LZW编码
LZW算法和LZ78算法在编码方式上的不同:
输出只包含码字,其目的是克服发送每段最后一个未压缩字符造成的低效率。
LZW只输出代表词典中的缀-符串的码字。这就意味着开始时词典不能为空。开始状态,词典中必须包含可能在字符流中出现的所有的单个字符,把这些单个字符称为前缀根。
LZW编码算法的步骤:
步骤1: 开始时的词典包含所有可能的根(Root),当前前缀P为空;
步骤2: 当前字符(Char) :=字符流中的下一个字符;
步骤3: 判断缀-符串P+ Char是否在词典中
(1) 如果”是”:P := P+ Char // (用Char扩展P) ;
(2) 如果”否”:① 把代表当前前缀P的码字输出到码字流;
② 把缀-符串P+ Char添加到词典;
③ 令P := Char //(现在P仅包含一个字符Char);
步骤4:判断字符流中是否还有字符需要编码
(1) 如果”是”,就返回到步骤2;
(2) 如果”否”
① 把代表当前前缀P的码字输出到码字流;
② 结束。
LZW译码过程:
开始时的词典包含所有可能的根(Root);
步骤1:当前码字(cW) :=码字流中的待解码的下一个码字;
查词典,输出Dictionary [cW];
步骤2:先前码字(pW):=当前码字(cW);
步骤3:判断码字流中是否还有需要解码的码字,
(1) 如果”是”:当前码字(cW) :=码字流中的待解码的下一个码字;
判断Dictionary [cW]是否为空(即词典中是否已经有序号为cW的项)
(a)如果”是”:
①查词典,输出Dictionary [cW];
②prefix:=Dictionary [pW] ;
③Char:=first Character of
Dictionary[cW] ;
④添加词典项Prefix+char;
⑤pW:=cW;
(b)如果”否”:
①prefix:=Dictionary [pW] ;
②Char:=first Character of prefix;
③添加词典项Prefix+char;
④查词典,输出Dictionary [cW];
⑤pW:=cW;
重复步骤3;
算法实现(C#)
/// <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.content == item)
return true;
return false;
}
/// <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=”str”></param>
public static void InitializeDictionary(string str) /*由于LZW算法必须有一个初始词典,因此在这里将词典初始化*/
{
foreach (char c in str)
{
if (!Find(c.ToString(), D))
{
AddToDic(c.ToString(), D);
}
}
}
/// <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.content == item)
return d.id;
return 0;
}
/// <summary>
/// 执行LZW编码算法
/// </summary>
/// <param name=”str”></param>
public static void Execute(string str)
{
char CHAR = (char)0;
string P = string.Empty;
InitializeDictionary(str);
foreach (char c in str)
{
CHAR = c;
if (Find((P+CHAR.ToString()), D))
{
P += CHAR;
}
else
{
Console.Write(“{0},“, GetDicID(P,D));
AddToDic(P + CHAR, D);
P = CHAR.ToString();
}
}
Console.Write(“{0}“, GetDicID(P, D));
Console.WriteLine();
}
}
/// <summary>
/// 解码器类
/// </summary>
public static class Decoder
{
/// <summary>
/// 词典
/// </summary>
static List<Dictionary> D = new List<Dictionary>();
/// <summary>
/// 初始化词典,解码算法中需手工输入
/// </summary>
public static void GetDictionary() //解码算法需手工输入初始词典
{
ShowInputHelp();
while (true)
{
string content = Console.ReadLine();
string[] items = content.Split(‘ ‘);
if (Convert.ToInt32(items[0]) != 0)
{
int id = Convert.ToInt32(items[0]);
string ch = items[1];
D.Add(new Dictionary(id, ch));
}
else break;
}
}
/// <summary>
/// 输入方法说明
/// </summary>
static void ShowInputHelp()
{
Console.WriteLine(“请输入初始词典:“);
Console.WriteLine(“格式:“);
Console.WriteLine(“每行输入一个条目,编号与字符串之间以逗号分隔,以0结束“);
}
/// <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.content;
}
return string.Empty;
}
/// <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>
/// 执行LZW解码算法
/// </summary>
/// <param name=”str”></param>
public static void Execute(string str)
{
string[] codeStream = str.Split(‘,’);
int cW = 0, pW = 0;
char CHAR = (char)0;
string prefix = string.Empty;
int count = 1;
foreach (string code in codeStream)
{
if (count == 1)
{
cW = Convert.ToInt32(code);
Console.Write(GetContext(cW, D));
pW = cW;
count++;
continue;
}
if (count > 1)
{
cW = Convert.ToInt32(code);
if (GetContext(cW, D) != string.Empty)
{
Console.Write(GetContext(cW, D));
prefix = GetContext(pW, D);
CHAR = GetContext(cW, D).First();
AddToDic(prefix + CHAR, D);
pW = cW;
}
else
{
prefix = GetContext(pW, D);
CHAR = prefix.First();
AddToDic(prefix + CHAR, D);
Console.Write(GetContext(cW, D));
pW = cW;
}
}
}
Console.WriteLine();
}
}
主函数代码省略,执行效果如下:
本例中要编码的字符串有14个字符,压缩后的编码有10个数字,按实际字节算,压缩率为65%。
最新评论