在计算机科学中,LZW压缩算法(Lempel-Ziv-Welch)是一种无损数据压缩技术,广泛应用于GIF图像、TIFF文件以及早期的Unix压缩工具。本教程将带你从零开始,用C语言实现LZW压缩与解码,即使你是编程小白也能轻松上手!

LZW由Abraham Lempel、Jacob Ziv和Terry Welch共同提出,其核心思想是:通过构建一个“字典”来记录已经出现过的字符串,并用较短的代码代替重复出现的字符串,从而实现压缩。
例如,原始字符串 ABABABA 中,“AB”重复出现。LZW会先将“AB”加入字典,之后再遇到“AB”就用一个数字(比如256)代替,从而减少数据量。
下面是一个简化但完整的LZW数据压缩实现。我们使用哈希表模拟字典,为便于理解,这里限制最大字典大小为4096(12位编码)。
#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX_DICT_SIZE 4096#define INIT_DICT_SIZE 256typedef struct { char* str; int code;} DictEntry;// 简易哈希函数unsigned int hash(const char* s) { unsigned int h = 0; while (*s) h = h * 31 + *s++; return h % MAX_DICT_SIZE;}// 在字典中查找字符串int find_in_dict(DictEntry dict[], const char* s) { unsigned int idx = hash(s); // 线性探测处理冲突 while (dict[idx].str != NULL) { if (strcmp(dict[idx].str, s) == 0) return dict[idx].code; idx = (idx + 1) % MAX_DICT_SIZE; } return -1;}// 添加新条目到字典void add_to_dict(DictEntry dict[], const char* s, int code) { if (code >= MAX_DICT_SIZE) return; unsigned int idx = hash(s); while (dict[idx].str != NULL) idx = (idx + 1) % MAX_DICT_SIZE; dict[idx].str = malloc(strlen(s) + 1); strcpy(dict[idx].str, s); dict[idx].code = code;}// LZW 压缩函数void lzw_compress(const char* input, FILE* out) { DictEntry dict[MAX_DICT_SIZE] = {0}; // 初始化字典:0-255 对应 ASCII 字符 for (int i = 0; i < INIT_DICT_SIZE; i++) { char s[2] = {i, '\0'}; add_to_dict(dict, s, i); } int next_code = INIT_DICT_SIZE; char current[100] = ""; for (int i = 0; input[i] != '\0'; i++) { char next[100]; sprintf(next, "%s%c", current, input[i]); if (find_in_dict(dict, next) != -1) { strcpy(current, next); } else { // 输出 current 的编码 int code = find_in_dict(dict, current); fwrite(&code, sizeof(int), 1, out); // 将 next 加入字典 if (next_code < MAX_DICT_SIZE) { add_to_dict(dict, next, next_code++); } // 重置 current 为当前字符 sprintf(current, "%c", input[i]); } } // 输出最后一个字符串的编码 if (strlen(current) > 0) { int code = find_in_dict(dict, current); fwrite(&code, sizeof(int), 1, out); }}解压过程不需要传输字典,而是根据压缩码流动态重建。这是LZW的巧妙之处!
// LZW 解压函数void lzw_decompress(FILE* in, FILE* out) { char dict[MAX_DICT_SIZE][100] = {0}; // 初始化字典 for (int i = 0; i < INIT_DICT_SIZE; i++) { dict[i][0] = (char)i; dict[i][1] = '\0'; } int next_code = INIT_DICT_SIZE; int prev_code, current_code; // 读取第一个编码 if (fread(&prev_code, sizeof(int), 1, in) == 0) return; fprintf(out, "%s", dict[prev_code]); while (fread(¤t_code, sizeof(int), 1, in)) { char* entry; if (current_code < next_code) { entry = dict[current_code]; } else if (current_code == next_code) { // 特殊情况:当前编码等于下一个可用编码 char temp[100]; sprintf(temp, "%s%c", dict[prev_code], dict[prev_code][0]); entry = temp; } else { fprintf(stderr, "错误:无效编码 %d\n", current_code); return; } fprintf(out, "%s", entry); // 将新字符串加入字典 if (next_code < MAX_DICT_SIZE) { sprintf(dict[next_code], "%s%c", dict[prev_code], entry[0]); next_code++; } prev_code = current_code; }}你可以这样调用上述函数:
int main() { const char* text = "ABABABA"; // 压缩 FILE* comp = fopen("compressed.lzw", "wb"); lzw_compress(text, comp); fclose(comp); // 解压 FILE* decomp = fopen("decompressed.txt", "w"); FILE* input = fopen("compressed.lzw", "rb"); lzw_decompress(input, decomp); fclose(input); fclose(decomp); printf("压缩与解压完成!\n"); return 0;}通过本教程,你已经掌握了LZW压缩算法的基本原理,并用C语言实现LZW完成了压缩与解码。虽然实际应用中需考虑更多边界情况(如字典溢出、跨平台兼容性等),但这个简化版本足以帮助你理解核心逻辑。
记住,LZW编码解码的关键在于动态构建字典,而LZW数据压缩的优势在于无需预先知道数据统计特性,非常适合通用场景。
现在,你可以尝试优化这段代码,比如改用更高效的哈希表、支持二进制文件、或增加命令行接口!
本文由主机测评网于2025-12-17发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025128996.html