C語(yǔ)言實(shí)現(xiàn)短字符串壓縮的三種方法詳解
前言
上一篇探索了LZ4的壓縮和解壓性能,以及對(duì)LZ4和ZSTD的壓縮、解壓性能進(jìn)行了橫向?qū)Ρ?。文末的最后也給了一個(gè)彩蛋:任意長(zhǎng)度的字符串都可以被ZSTD、LZ4之類的壓縮算壓縮得很好嗎?
本篇我們就來(lái)一探究竟。
一、通用算法的短字符壓縮
開門見山,我們使用一段比較短的文本:Narrator: It is raining today. So, Peppa and George cannot play outside.Peppa: Daddy, it's stopped raining.
使用ZSTD與LZ4分別壓縮一下上面這段短文本。下面分別是它們的壓縮結(jié)果。
ZSTD:
LZ4:
對(duì)短文本的壓縮,zstd的壓縮率很低,lz4壓縮后的文本長(zhǎng)度盡然超過了原有字符串的長(zhǎng)度。這是為什么?說(shuō)實(shí)話在這之前我也沒想到。
引用兩位大佬的名言:
Are you ok?
What's your problem?
二、短字符串壓縮
從上面的結(jié)果可以得知,任何壓縮算法都有它的使用場(chǎng)景,并不是所有長(zhǎng)度的字符串都適合被某種算法壓縮。一般原因是通用壓縮算法維護(hù)了被壓縮字符串的,用于字符串還原的相關(guān)數(shù)據(jù)結(jié)構(gòu),而這些數(shù)據(jù)結(jié)構(gòu)的長(zhǎng)度超過了被壓縮短字符串的自身長(zhǎng)度。
那么問題來(lái)了,“我真的有壓縮短字符串的需求,我想體驗(yàn)壓縮的極致感,怎么辦?”。
短字符壓縮算法它來(lái)了。這里挑選了3種比較優(yōu)異的短字符壓縮算法,分別是smaz,shoco,以及壓軸的unisox2。跟前兩章一樣,還是從壓縮率,壓縮和解壓縮性能的角度,一起看看他們?cè)诙套址麎嚎s場(chǎng)景的各自表現(xiàn)吧。
(1)Smaz
1、Smaz的壓縮和解壓縮
#include <stdio.h> #include <string.h> #include <iostream> #include "smaz.h" using namespace std; int main() { int buf_len; int com_size; int decom_size; char com_buf[4096] = {0}; char decom_buf[4096] = {0}; char str_buf[1024] = "Narrator: It is raining today. So, Peppa and George cannot play outside.Peppa: Daddy, it's stopped raining."; buf_len = strlen(str_buf); com_size = smaz_compress(str_buf, buf_len, com_buf, 4096); cout << "text size:" << buf_len << endl; cout << "compress text size:" << com_size << endl; cout << "compress ratio:" << (float)buf_len / (float)com_size << endl << endl; decom_size = smaz_decompress(com_buf, com_size, decom_buf, 4096); cout << "decompress text size:" << decom_size << endl; if(strncmp(str_buf, decom_buf, buf_len)) { cout << "decompress text is not equal to source text" << endl; } return 0; }
執(zhí)行結(jié)果如下:
通過smaz壓縮后的短字符串長(zhǎng)度為77,和源字符串相比,減少了30Byte。
2、Smaz的壓縮和解壓縮性能
#include <stdio.h> #include <string.h> #include <iostream> #include <sys/time.h> #include "smaz.h" using namespace std; int main() { int cnt = 0; int buf_len; int com_size; int decom_size; timeval st, et; char *com_ptr = NULL; char* decom_ptr = NULL; char str_buf[1024] = "Narrator: It is raining today. So, Peppa and George cannot play outside.Peppa: Daddy, it's stopped raining."; buf_len = strlen(str_buf); gettimeofday(&st, NULL); while(1) { com_ptr = (char *)malloc(buf_len); com_size = smaz_compress(str_buf, buf_len, com_ptr, buf_len); free(com_ptr); cnt++; gettimeofday(&et, NULL); if(et.tv_sec - st.tv_sec >= 10) { break; } } cout << endl <<"compress per second:" << cnt/10 << " times" << endl; cnt = 0; com_ptr = (char *)malloc(buf_len); com_size = smaz_compress(str_buf, buf_len, com_ptr, buf_len); gettimeofday(&st, NULL); while(1) { // decompress length not more than origin buf length decom_ptr = (char *)malloc(buf_len + 1); decom_size = smaz_decompress(com_ptr, com_size, decom_ptr, buf_len + 1); // check decompress length if(buf_len != decom_size) { cout << "decom error" << endl; } free(decom_ptr); cnt++; gettimeofday(&et, NULL); if(et.tv_sec - st.tv_sec >= 10) { break; } } cout << "decompress per second:" << cnt/10 << " times" << endl << endl; free(com_ptr); return 0; }
結(jié)果如何?
壓縮性能在40w條/S,解壓在百萬(wàn)級(jí),好像還不錯(cuò)哈!
(2)Shoco
1、Shoco的壓縮和解壓縮
#include <stdio.h> #include <string.h> #include <iostream> #include "shoco.h" using namespace std; int main() { int buf_len; int com_size; int decom_size; char com_buf[4096] = {0}; char decom_buf[4096] = {0}; char str_buf[1024] = "Narrator: It is raining today. So, Peppa and George cannot play outside.Peppa: Daddy, it's stopped raining."; buf_len = strlen(str_buf); com_size = shoco_compress(str_buf, buf_len, com_buf, 4096); cout << "text size:" << buf_len << endl; cout << "compress text size:" << com_size << endl; cout << "compress ratio:" << (float)buf_len / (float)com_size << endl << endl; decom_size = shoco_decompress(com_buf, com_size, decom_buf, 4096); cout << "decompress text size:" << decom_size << endl; if(strncmp(str_buf, decom_buf, buf_len)) { cout << "decompress text is not equal to source text" << endl; } return 0; }
執(zhí)行結(jié)果如下:
通過shoco壓縮后的短字符串長(zhǎng)度為86,和源字符串相比,減少了21Byte。壓縮率比smaz要低。
2、Shoco的壓縮和解壓縮性能
#include <stdio.h> #include <string.h> #include <iostream> #include <sys/time.h> #include "shoco.h" using namespace std; int main() { int cnt = 0; int buf_len; int com_size; int decom_size; timeval st, et; char *com_ptr = NULL; char* decom_ptr = NULL; char str_buf[1024] = "Narrator: It is raining today. So, Peppa and George cannot play outside.Peppa: Daddy, it's stopped raining."; buf_len = strlen(str_buf); gettimeofday(&st, NULL); while(1) { com_ptr = (char *)malloc(buf_len); com_size = shoco_compress(str_buf, buf_len, com_ptr, buf_len); free(com_ptr); cnt++; gettimeofday(&et, NULL); if(et.tv_sec - st.tv_sec >= 10) { break; } } cout << endl <<"compress per second:" << cnt/10 << " times" << endl; cnt = 0; com_ptr = (char *)malloc(buf_len); com_size = shoco_compress(str_buf, buf_len, com_ptr, buf_len); gettimeofday(&st, NULL); while(1) { // decompress length not more than origin buf length decom_ptr = (char *)malloc(buf_len + 1); decom_size = shoco_decompress(com_ptr, com_size, decom_ptr, buf_len + 1); // check decompress length if(buf_len != decom_size) { cout << "decom error" << endl; } free(decom_ptr); cnt++; gettimeofday(&et, NULL); if(et.tv_sec - st.tv_sec >= 10) { break; } } cout << "decompress per second:" << cnt/10 << " times" << endl << endl; free(com_ptr); return 0; }
執(zhí)行結(jié)果如何呢?
holy shit!壓縮和解壓縮居然都達(dá)到了驚人的百萬(wàn)級(jí)。就像算法作者們自己說(shuō)的一樣:“在長(zhǎng)字符串壓縮領(lǐng)域,shoco不想與通用壓縮算法競(jìng)爭(zhēng),我們的優(yōu)勢(shì)是短字符的快速壓縮,雖然壓縮率很爛!”。這樣說(shuō),好像也沒毛病。
(3)Unisox2
我們?cè)賮?lái)看看unisox2呢。
1、Unisox2的壓縮和解壓縮
#include <stdio.h> #include <string.h> #include "unishox2.h" int main() { int buf_len; int com_size; int decom_size; char com_buf[4096] = {0}; char decom_buf[4096] = {0}; char str_buf[1024] = "Narrator: It is raining today. So, Peppa and George cannot play outside.Peppa: Daddy, it's stopped raining."; buf_len = strlen(str_buf); com_size = unishox2_compress_simple(str_buf, buf_len, com_buf); printf("text size:%d\n", buf_len); printf("compress text size:%d\n", com_size); printf("compress ratio:%f\n\n", (float)buf_len / (float)com_size); decom_size = unishox2_decompress_simple(com_buf, com_size, decom_buf); printf("decompress text size:%d\n", decom_size); if(strncmp(str_buf, decom_buf, buf_len)) { printf("decompress text is not equal to source text\n"); } return 0; }
結(jié)果如下:
通過Unisox2壓縮后的短字符串長(zhǎng)度為67,和源字符串相比,減少了40Byte,相當(dāng)于是打了6折??!不錯(cuò)不錯(cuò)。
2、Unisox2的壓縮和解壓縮性能
Unisox2的壓縮能力目前來(lái)看是三者中最好的,如果他的壓縮和解壓性能也不錯(cuò)的話,那就真的就比較完美了。再一起看看Unisox2的壓縮和解壓性能吧!
#include <stdio.h> #include <string.h> #include <malloc.h> #include <sys/time.h> #include "unishox2.h" int main() { int cnt = 0; int buf_len; int com_size; int decom_size; struct timeval st, et; char *com_ptr = NULL; char* decom_ptr = NULL; char str_buf[1024] = "Narrator: It is raining today. So, Peppa and George cannot play outside.Peppa: Daddy, it's stopped raining."; buf_len = strlen(str_buf); gettimeofday(&st, NULL); while(1) { com_ptr = (char *)malloc(buf_len); com_size = unishox2_compress_simple(str_buf, buf_len, com_ptr); free(com_ptr); cnt++; gettimeofday(&et, NULL); if(et.tv_sec - st.tv_sec >= 10) { break; } } printf("\ncompress per second:%d times\n", cnt/10); cnt = 0; com_ptr = (char *)malloc(buf_len); com_size = unishox2_compress_simple(str_buf, buf_len, com_ptr); gettimeofday(&st, NULL); while(1) { // decompress length not more than origin buf length decom_ptr = (char *)malloc(buf_len + 1); decom_size = unishox2_decompress_simple(com_ptr, com_size, decom_ptr); // check decompress length if(buf_len != decom_size) { printf("decom error\n"); } free(decom_ptr); cnt++; gettimeofday(&et, NULL); if(et.tv_sec - st.tv_sec >= 10) { break; } } printf("decompress per second:%d times\n\n", cnt/10); free(com_ptr); return 0; }
執(zhí)行結(jié)果如下:
事與愿違,Unisox2雖然有三個(gè)算法中最好的壓縮率,可是卻也擁有最差的壓縮和解壓性能。跟前兩章分析的不謀而合:有高壓縮率,就會(huì)損失自身的壓縮性能,兩者不可兼得。
三、總結(jié)
本篇分享了smaz,shoco,unisox2三種短字符串壓縮算法,分別探索了它們各自的壓縮率與壓縮和解壓縮性能,結(jié)果如下表所示。
表1
shoco的壓縮率最低,但是擁有最高的壓縮和解壓速率;smaz居中;unisox2擁有最高的壓縮率,可是它的壓縮和解壓性能最低。
結(jié)論與前兩章有關(guān)長(zhǎng)字符串壓縮的分析不謀而合:擁有高壓縮率,就會(huì)損失自身的壓縮性能,兩者不可兼得。
實(shí)際使用還是看自身需求和環(huán)境吧。如果適當(dāng)壓縮就好,那就可以選用shoco,畢竟性能高;想要節(jié)約更多的空間,那就選擇smaz或者unisox2。
到此這篇關(guān)于C語(yǔ)言實(shí)現(xiàn)短字符串壓縮的三種方法詳解的文章就介紹到這了,更多相關(guān)C語(yǔ)言短字符串壓縮內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言雙向鏈表的表示與實(shí)現(xiàn)實(shí)例詳解
這篇文章主要介紹了C語(yǔ)言雙向鏈表的表示與實(shí)現(xiàn),對(duì)于研究數(shù)據(jù)結(jié)構(gòu)域算法的朋友有一定的參考借鑒價(jià)值,需要的朋友可以參考下2014-07-07詳解如何從Matlab中導(dǎo)出清晰的結(jié)果圖片
寫文章的時(shí)候有時(shí)需要matlab導(dǎo)出清晰的圖片,如果直接用figure里面的保存的話不夠清晰,下面這篇文章主要給大家介紹了關(guān)于如何從Matlab中導(dǎo)出清晰的結(jié)果圖片的相關(guān)資料,需要的朋友可以參考下2022-06-06VC獲取當(dāng)前路徑及程序名的實(shí)現(xiàn)代碼
VC上或取當(dāng)前路徑有多種方法,最常用的是使用 GetCurrentDirectory和GetModuleFileName函數(shù),個(gè)中都有諸多注意事項(xiàng),特別總結(jié)一下2016-11-11詳解C語(yǔ)言中printf輸出的相關(guān)函數(shù)
這篇文章主要介紹了C語(yǔ)言中printf輸出的相關(guān)函數(shù)總結(jié),是C語(yǔ)言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-08-08C++淺析數(shù)據(jù)在內(nèi)存中如何存儲(chǔ)
使用編程語(yǔ)言進(jìn)行編程時(shí),需要用到各種變量來(lái)存儲(chǔ)各種信息。變量保留的是它所存儲(chǔ)的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個(gè)變量時(shí),就會(huì)在內(nèi)存中保留一些空間。您可能需要存儲(chǔ)各種數(shù)據(jù)類型的信息,操作系統(tǒng)會(huì)根據(jù)變量的數(shù)據(jù)類型,來(lái)分配內(nèi)存和決定在保留內(nèi)存中存儲(chǔ)什么2022-08-08解析在Direct2D中畫Bezier曲線的實(shí)現(xiàn)方法
本篇文章是對(duì)在Direct2D中畫Bezier曲線的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05