LZW算法
步骤如下:
初始化字典:创建一个初始字典,其中包含所有可能的输入符号。
输入处理:读取输入数据,并将第一个输入符号作为当前模式。
模式匹配和字典更新:从输入中读取下一个符号,并将当前模式与已有字典中的模式进行匹配。
如果匹配成功,将当前模式与下一个输入符号拼接,得到一个新的模式,继续进行匹配。
如果匹配失败,将当前模式的编码输出,并将当前模式与下一个输入符号作为新的模式。
编码输出:将最后一个匹配成功的模式的编码输出。
字典更新:将最后一个匹配成功的模式与下一个输入符号拼接,将这个新的模式添加到字典中。
重复步骤3-5,直到所有输入数据被处理完毕。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_DICT_SIZE 4096typedef struct {int code;char* pattern;
} Entry;void compress(FILE* inputFile, FILE* outputFile) {Entry dict[MAX_DICT_SIZE];int dictSize = 256; // 初始字典大小为256,表示ASCII字符// 初始化字典for (int i = 0; i < 256; i++) {dict[i].code = i;dict[i].pattern = (char*)malloc(2 * sizeof(char));dict[i].pattern[0] = (char)i;dict[i].pattern[1] = '\0';}int currentCode = 0; //0char currentSymbol;char nextSymbol;char* currentPattern = (char*)malloc(2 * sizeof(char));currentPattern[0] = fgetc(inputFile); //初始状态,字典里只有所有的默认项currentPattern[1] = '\0';while ((nextSymbol = fgetc(inputFile)) != EOF) {char* nextPattern = (char*)malloc((strlen(currentPattern) + 2) * sizeof(char));strcpy(nextPattern, currentPattern);strncat(nextPattern, &nextSymbol, 1);//读入新的字符C,与P合并形成字符串P+Cint found = 0;for (int i = 0; i < dictSize; i++) {// 在字典里查找P+Cif (strcmp(dict[i].pattern, nextPattern) == 0) {currentPattern = nextPattern;found = 1; //P+C在字典里break;}}if (!found) {//P+C不在字典里,将P的记号输出;在字典中为P+C建立一个记号映射;更新P=Cfwrite(&dict[currentCode].code, sizeof(int), 1, outputFile);if (dictSize < MAX_DICT_SIZE) {dict[dictSize].code = dictSize;dict[dictSize].pattern = (char*)malloc((strlen(nextPattern) + 1) * sizeof(char));strcpy(dict[dictSize].pattern, nextPattern);dictSize++;}currentPattern = (char*)malloc(2 * sizeof(char));currentPattern[0] = nextSymbol;currentPattern[1] = '\0';currentCode = nextSymbol;}}fwrite(&dict[currentCode].code, sizeof(int), 1, outputFile);// 释放内存for (int i = 0; i < dictSize; i++) {free(dict[i].pattern);}free(currentPattern);
}int main() {FILE* inputFile = fopen("input.txt", "r");FILE* compressedFile = fopen("compressed.bin", "wb");compress(inputFile, compressedFile);fclose(inputFile);fclose(compressedFile);return 0;
}
#include <iostream>
#include <string>
#include <cstring>#define NotExist -1
#define MaxSize 1000using namespace std;typedef struct Dictionary{char **seq; // 字符串集合int *code; // 字符串编码的集合int size; // 字典的大小int maxsize; // 字典的最大长度
}Dictionary, *PDictionary;// 向字典中插入一条数据
void insert_seq(PDictionary dict, int code, char* seq)
{if (dict->size == dict->maxsize){printf("字典已满,插入失败!");return;}int i = dict->size;dict->code[i] = code;dict->seq[i] = (char*)malloc(sizeof(char) * strlen(seq) + 1);strcpy(dict->seq[i], seq);dict->size++;return;
}// 初始化字典
void initDict(PDictionary dict, int maxsize)
{dict->maxsize = maxsize;dict->size = 0;dict->code = (int*)malloc(sizeof(int) * maxsize);dict->seq = (char**)malloc(sizeof(char*) * maxsize + 1);// 初始化时先放入‘A’~‘Z’char seq[2] = "A";for (int i = 0; i < 26; i++){insert_seq(dict, i, seq);seq[0]++;}return;
}// 打印字典
void print_dict(PDictionary dict)
{printf("===================\n");printf("Code Seq\n");for (int i = 0; i < dict->size; i++){printf("%4d%7s\n", dict->code[i], dict->seq[i]);}return;
}// 查找字典中有无seq
int is_exist_seq(PDictionary dict, char *seq)
{for (int i = 0; i < dict->size; i++){if (strcmp(seq, dict->seq[i]) == 0){return dict->code[i];}}return NotExist;
}// 根据编码查找Seq
char* find_seq(PDictionary dict, int code)
{return dict->seq[code];
}// LZW编码
void lzw_encode(PDictionary dict, char* text)
{char cur[MaxSize];char next;int code;char seq[MaxSize];int i = 0;int len = strlen(text);while (i < len){sprintf(cur, "%c", text[i]);while (is_exist_seq(dict, cur) != NotExist && i < len){i++;sprintf(cur, "%s%c", cur, text[i]);}if (i < len) {insert_seq(dict, dict->size, cur);cur[strlen(cur) - 1] = '\0';}code = is_exist_seq(dict, cur);printf("%d,", code, cur);}return;
}// LZE解码
void lzw_decode(PDictionary dict, int *code, int size)
{char *pre = NULL;int i = 0;char str[MaxSize];while (i < size){strcpy(str, find_seq(dict, code[i]));printf("%s", str);if (pre != NULL){char tmp[MaxSize];sprintf(tmp, "%s%c", pre, str[0]);insert_seq(dict, dict->size, tmp);}pre = (char*)malloc(sizeof(char) * strlen(str) + 1);strcpy(pre, str);i++;}printf("\n");return;
}int main()
{Dictionary dict;int code[] = { 8, 11, 14, 21, 4, 24, 14, 20, 26, 28, 30, 32, 3, 14, 31, 20, 27, 29, 12, 4, 38, 40, 42, 4, 44 };int size = 25;initDict(&dict, MaxSize);//lzw_encode(&dict, "ILOVEYOUILOVEYOUDOYOULOVEMEDOYOULOVEME");lzw_decode(&dict, code, size);//print_dict(&dict);return 0;
}
JPEG压缩算法
步骤如下:
将彩色图像转换为亮度和色度分量。对于彩色图像,首先将其转换为亮度(Y)和色度(Cb和Cr)分量,以便对亮度和色度进行独立的压缩。
对每个分量进行图像分块。将亮度和色度分量划分为8x8的图像块。
对每个图像块进行离散余弦变换(DCT)。对于每个8x8的图像块,应用离散余弦变换,将图像从空域转换到频域。
对DCT系数进行量化。将DCT系数进行量化,减少高频成分的精度,从而实现数据的压缩。
进行熵编码。对量化后的DCT系数进行熵编码,使用哈夫曼编码或其他熵编码算法来实现数据的进一步压缩。
重构图像。解码器根据压缩数据和解码过程的逆操作,对量化系数进行逆量化和逆DCT变换,以重构原始图像。
# 导入所需的库
import numpy as np
from scipy.fftpack import dct# 定义JPEG压缩函数
def jpeg_compress(image):# 将图像块划分为8x8的块blocks = image.reshape(-1, 8, 8)# 对每个图像块进行DCT变换dct_blocks = np.zeros_like(blocks)for i in range(blocks.shape[0]):dct_blocks[i] = dct(dct(blocks[i], axis=0), axis=1)# 对DCT系数进行量化quantized_blocks = np.round(dct_blocks / quantization_table)# 对量化后的系数进行熵编码等进一步压缩步骤# 返回压缩后的数据return quantized_blocks# 定义量化表
quantization_table = np.array([[16, 11, 10, 16, 24, 40, 51, 61],[12, 12, 14, 19, 26, 58, 60, 55],[14, 13, 16, 24, 40, 57, 69, 56],[14, 17, 22, 29, 51, 87, 80, 62],[18, 22, 37, 56, 68, 109, 103, 77],[24, 35, 55, 64, 81, 104, 113, 92],[49, 64, 78, 87, 103, 121, 120, 101],[72, 92, 95, 98, 112, 100, 103, 99]
])# 读取图像数据
image = read_image("input.jpg")# 调用JPEG压缩函数
compressed_data = jpeg_compress(image)# 保存压缩后的数据
save_compressed_data(compressed_data, "compressed.jpg")
无损压缩算
哈夫曼编码:具有较高的压缩比率和解压速度,适用于文本数据和较小的数据集。质量无损。
LZW算法:具有较高的压缩比率和解压速度,适用于文本和图像数据。质量无损。
预测编码:如算术编码和差分编码,压缩比率较高,但解压速度较慢。质量无损。
有损压缩算法:
JPEG压缩算法:适用于图像压缩,具有较高的压缩比率和解压速度,但会引入一定的图像质量损失。
MP3压缩算法:适用于音频压缩,具有较高的压缩比率和解压速度,但会引入一定的音质损失。
视频编码算法:如H.264、HEVC等,具有较高的压缩比率和解压速度,但会引入一定的视频质量损失
RLE(Run Length Encoding)
文件内容——数据*重复次数
ABCDEFG经压缩后将成为1A1B1C1D1E1F1G,