代碼示例|一文讀懂壓縮算法
概述
本文引用地址:http://www.ex-cimer.com/article/202412/465146.htm壓縮算法是一種通過減少數(shù)據(jù)量來節(jié)省存儲空間或傳輸數(shù)據(jù)的技術(shù)。壓縮算法可以分為兩種類型:有損壓縮和無損壓縮。
· 有損壓縮算法會犧牲一定的數(shù)據(jù)精度或質(zhì)量,在壓縮數(shù)據(jù)的同時丟失一些信息。這種算法適用于音頻、視頻等多媒體數(shù)據(jù),例如JPEG和MP3等格式。
· 無損壓縮算法則能夠完全還原原始數(shù)據(jù),不會造成數(shù)據(jù)丟失。這種算法適用于需要準(zhǔn)確還原數(shù)據(jù)的場景,如文檔、代碼等,例如ZIP和GZIP等格式。
常見的壓縮算法包括哈夫曼編碼、Lempel-Ziv算法、Run-Length Encoding(RLE)等。這些算法通過不同的方式對數(shù)據(jù)進行編碼和解碼,以實現(xiàn)數(shù)據(jù)壓縮和解壓縮的目的。
壓縮算法的應(yīng)用
壓縮算法在各種領(lǐng)域廣泛應(yīng)用,包括但不限于以下幾個方面:
· 文件傳輸和存儲:壓縮算法可以減少文件的大小,使文件傳輸更加高效快速。在網(wǎng)絡(luò)傳輸、電子郵件附件、云存儲等場景下,壓縮算法可以節(jié)省帶寬和存儲空間。
· 多媒體數(shù)據(jù):音頻、視頻等多媒體數(shù)據(jù)通常是體積較大的,使用壓縮算法可以減少文件大小,提高數(shù)據(jù)的傳輸速度和播放效果。常見的視頻壓縮算法包括H.264、HEVC等;音頻壓縮算法包括MP3、AAC等。
· 數(shù)據(jù)庫壓縮:在數(shù)據(jù)庫管理系統(tǒng)中,數(shù)據(jù)通常存儲在磁盤上,通過壓縮算法可以減少數(shù)據(jù)占用的存儲空間,并提高數(shù)據(jù)庫的性能和響應(yīng)速度。
· 圖像處理:在數(shù)字圖像處理中,壓縮算法可以減小圖像文件的大小,在圖像傳輸和存儲中起到重要作用。常見的圖像壓縮算法包括JPEG、PNG等。
· 網(wǎng)頁內(nèi)容壓縮:為了減少網(wǎng)頁加載時間和用戶訪問流量,網(wǎng)站通常會使用壓縮算法對HTML、CSS、JavaScript等網(wǎng)頁內(nèi)容進行壓縮,提高用戶體驗和網(wǎng)站性能。
總的來說,壓縮算法在信息技術(shù)領(lǐng)域的各個方面都有廣泛的應(yīng)用,可以有效地節(jié)省存儲空間、提高數(shù)據(jù)傳輸效率和優(yōu)化性能。
適合ARM跑的壓縮算法
ARM架構(gòu)是一種廣泛應(yīng)用于移動設(shè)備、嵌入式系統(tǒng)和物聯(lián)網(wǎng)設(shè)備中的處理器架構(gòu)。在運行在ARM處理器上的設(shè)備或系統(tǒng)上選擇合適的壓縮算法,需要考慮算法的性能、資源消耗和適應(yīng)性。
以下是一些適合與ARM跑的壓縮算法:
· Zstandard(Zstd):Zstandard是一種快速的壓縮算法,性能優(yōu)秀,并且可以在ARM處理器上高效運行。它具有適應(yīng)性強,可以在不同的場景下應(yīng)用,如數(shù)據(jù)傳輸、數(shù)據(jù)庫壓縮等。
· LZ4:LZ4是一種高速壓縮算法,適合于需要快速壓縮和解壓的場景。它具有低延遲和高吞吐量的特點,適合在ARM處理器上運行。LZ4是一種LZ系列壓縮算法,著重于壓縮和解壓的速度,壓縮率相對較低。LZ4壓縮率較低,算法復(fù)雜度和內(nèi)存消耗中等,但是壓縮和解壓速度,尤其是解壓速度遠超其他算法。因為其綜合性能優(yōu)秀,在Linux、Android中的內(nèi)存壓縮技術(shù)一般使用LZ4壓縮算法。LZ4 HC,有著更好的壓縮率,但是算法復(fù)雜度大幅提升,且壓縮速度也大幅減慢。
· Brotli:Brotli是由Google開發(fā)的一種通用壓縮算法,特點是高壓縮率和較好的性能。它在文件傳輸、網(wǎng)絡(luò)傳輸?shù)葓鼍跋卤憩F(xiàn)優(yōu)異,也可以在ARM處理器上高效運行。
· Snappy:Snappy是Google開發(fā)的一種快速壓縮算法,適合于需要高速壓縮和解壓的場景。它在ARM處理器上表現(xiàn)優(yōu)秀,適用于數(shù)據(jù)傳輸、日志壓縮等應(yīng)用。
· Deflate(如zlib):Deflate是一種常見的無損壓縮算法,廣泛應(yīng)用于各種領(lǐng)域。zlib是實現(xiàn)Deflate算法的一個流行庫,也可以在ARM處理器上使用,并具有較好的性能。
這些壓縮算法在ARM處理器上都有良好的性能表現(xiàn),可以根據(jù)具體的應(yīng)用場景和需求選擇合適的算法。值得注意的是,優(yōu)化算法的實現(xiàn)、調(diào)整參數(shù)和選擇合適的壓縮級別,也可以進一步提高在ARM處理器上的性能表現(xiàn)。
Huffman霍夫曼(Huffman)編碼使用變長編碼表對源符號進行編碼,其中變長編碼表是通過一種評估來源符號出現(xiàn)機率的方法得到的,出現(xiàn)機率高的字母使用較短的編碼,反之出現(xiàn)機率低的則使用較長的編碼,這便使編碼之后的字符串的平均長度、期望值降低,從而達到無損壓縮數(shù)據(jù)的目的。霍夫曼編碼使用的編碼表,使用霍夫曼樹來進行存儲,讓出現(xiàn)概率最高的編碼最容易查找,以提升解碼速度?;舴蚵幋a算法的壓縮率分布在20%-90%,因為要掃描整個數(shù)據(jù)來構(gòu)建霍夫曼樹,所以其壓縮速度較慢,且需要一定的內(nèi)存來存儲編碼表,但是解壓速度較快?;舴蚵乃惴◤?fù)雜度較簡單。
RLE(Run Length Encoding),也稱為行程編碼,壓縮算法是一種無損壓縮算法。算法特點:簡單、易實現(xiàn)。使用RLE壓縮方法可以將 RRRRRGGBBBBBBABCD 壓縮為 5R2G6B1A1B1C1D?;赗LE算法升級,可以將RRRRRGGBBBBBBABCD可以壓縮為b’x85Rx82Gx86Bx03ABCD’,0x85表示后面有5個相同的字符,0x03表示后面有3個不連續(xù)的字符。RLE的實現(xiàn)非常簡單,針對一些圖片顏色少或重復(fù)字符多的文件有非常好的壓縮率,RLE的適用場景比較少,通用壓縮率較差。
LZ77是一種基于字典的算法,它將長字符串(也稱為短語)編碼成短小的標(biāo)記,用小標(biāo)記代替字典中的短語,從而達到壓縮的目的。LZ77算法的壓縮率、速度、內(nèi)存消費都是中等,但是代碼復(fù)雜度較低,適用于MCU的使用。
LZO壓縮算法采用(重復(fù)長度L,指回距離D)代替當(dāng)前已經(jīng)在歷史字符串中出現(xiàn)過的字符串。LZO致力于解壓速度,不同的參數(shù)下的LZO壓縮率不同。LZO內(nèi)存消耗中等,解壓速度較快,壓縮速度較快,但是代碼復(fù)雜度較低,適用于Bootloader等追求壓縮率和解壓速度的場景。
性能排序
在實際應(yīng)用中,不同的壓縮算法因為適用場景、數(shù)據(jù)類型、硬件平臺等因素的不同,其性能表現(xiàn)也會有所差異。以下是一些常見的壓縮算法按照一般趨勢的性能排序:
壓縮率(從高到低):
有損壓縮:JPEG2000 > WebP > H.265 (HEVC) > H.264 (AVC) > JPEG
無損壓縮:FLIF > Brotli > Zstandard > LZMA (7-Zip) > DEFLATE (zlib)
壓縮速度(從快到慢):
Snappy > LZ4 > Zstandard > Deflate (zlib) > Brotli
這里的快慢僅作為一般參考,具體情況因數(shù)據(jù)大小、數(shù)據(jù)類型、硬件性能等因素可能有所不同。
解壓速度(從快到慢):
Snappy > LZ4 > Zstandard > Deflate (zlib) > Brotli
同樣,解壓速度也會受到實際場景的影響,不同算法適用于不同的應(yīng)用需求。
內(nèi)存消耗(從少到多):
Snappy > LZ4 > Zstandard > Deflate (zlib) > Brotli
內(nèi)存消耗較低的壓縮算法可以在受限制的環(huán)境下更好地工作,如嵌入式設(shè)備等。
壓縮算法代碼示例
以下是一個簡單的使用zlib庫進行數(shù)據(jù)壓縮和解壓縮的C語言示例代碼:
```c
```c
#include
#include
#include
#include
#define CHUNK 16384
int compress_data(unsigned char* data, int data_len, unsigned char* compressed_data, int* compressed_len) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
if(deflateInit(&strm, Z_BEST_COMPRESSION) != Z_OK) {
return -1;
}
strm.avail_in = data_len;
strm.next_in = data;
strm.avail_out = *compressed_len;
strm.next_out = compressed_data;
int ret = deflate(&strm, Z_FINISH);
*compressed_len = strm.total_out;
deflateEnd(&strm);
return ret == Z_STREAM_END ? 0 : -1;
}
int decompress_data(unsigned char* compressed_data, int compressed_len, unsigned char* decompressed_data, int* decompressed_len) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
if(inflateInit(&strm) != Z_OK) {
return -1;
}
strm.avail_in = compressed_len;
strm.next_in = compressed_data;
strm.avail_out = *decompressed_len;
strm.next_out = decompressed_data;
int ret = inflate(&strm, Z_NO_FLUSH);
*decompressed_len = strm.total_out;
inflateEnd(&strm);
return ret == Z_STREAM_END ? 0 : -1;
}
int main() {
unsigned char data[] = "Hello, this is a test message!";
int data_len = strlen(data);
int compressed_size = compressBound(data_len);
unsigned char compressed_data[compressed_size];
int compressed_len = compressed_size;
if(compress_data(data, data_len, compressed_data, &compressed_len) == 0) {
printf("Data compressed successfully!n");
printf("Compressed data size: %dn", compressed_len);
unsigned char decompressed_data[data_len];
int decompressed_len = data_len;
if(decompress_data(compressed_data, compressed_len, decompressed_data, &decompressed_len) == 0) {
printf("Data decompressed successfully!n");
printf("Decompressed data: %sn", decompressed_data);
} else {
printf("Error decompressing data!n");
}
} else {
printf("Error compressing data!n");
}
return 0;
}
在這個示例代碼中,我們使用了zlib庫提供的函數(shù)進行數(shù)據(jù)壓縮和解壓縮操作。壓縮函數(shù) compress_data 將輸入數(shù)據(jù)進行壓縮,并將壓縮后的數(shù)據(jù)存儲在 compressed_data 中,返回壓縮后的數(shù)據(jù)長度;解壓縮函數(shù) decompress_data 對壓縮后的數(shù)據(jù)進行解壓縮,并將解壓縮后的數(shù)據(jù)存儲在 decompressed_data 中,返回解壓縮后的數(shù)據(jù)長度。在主函數(shù)中,我們對一個簡單的字符串進行壓縮和解壓縮操作,并輸出結(jié)果。
請注意,這段示例代碼使用了zlib庫,因此在編譯時需要鏈接zlib庫。在Linux系統(tǒng)下,可以使用 -lz 選項進行鏈接。
評論