數據壓縮的重要組成部分---位操做

數據壓縮描述

數據壓縮是一個減小數據存儲空間的過程。數據結構

數據壓縮包括兩個過程:一個過程是,壓縮或編碼數據,數據大小減少;另外一個過程是,解壓縮或解碼數據,還原到數據自己的狀態。函數

根據信息的內容,全部的數據都會表現出必定的特性,稱爲熵(從熱力學借用的一個術語)。壓縮是可能的,由於絕大多數數據所表現出來的容量都大於其熵所建議的最佳容量。爲了衡量壓縮的效率,一般用1減去壓縮數據大小除以原始數據大小的值。這個值稱爲數據的壓縮率。學習

從廣義上講,數據壓縮的方法分爲兩大類:有損壓縮和無損壓縮。在有損壓縮中,咱們接受數據有必定的損失來換取更大的壓縮比。在某些應用中,必定的損失是能夠接受的,好比圖像或音頻的處理,由於這種損失不會影響其效果而且會受到嚴格控制。然而,咱們一般使用的是無損壓縮,它可以保證解壓縮時準確的還原原始數據。編碼

咱們重點介紹無損壓縮,實現無損壓縮主要有兩種方法:最小冗餘編碼和基於字典的方法。最小冗餘編碼使用更少的位對出現更爲頻繁的字符進行編碼,用較長的位對出現頻繁較低的字符進行編碼。在基於字典的方法中,其經過對數據進行符號編碼,來代替那些重複多餘的短語。加密

數據壓縮的重要組成部分

位操做是數據壓縮的重要組成部分,由於絕大多數方法在某種程度上都須要對數據的位進行操做。C語言自己提供了一些位操做的接口,能夠用這些接口來實現一些擴展的位操做類。spa

咱們先來看一下數據壓縮的頭文件(在數據壓縮介紹中必不可少,包括各類符號常量、壓縮、解壓縮的接口等):指針

/*compress.h 數據壓縮的頭文件*/ #ifndef COMPRESS_H #define COMPRESS_H #include "bitree.h"

/*定義霍夫曼樹的節點數據結構*/ typedef struct HuffNode_ { unsigned char symbol; int freq; }HuffNode; /*定義霍夫曼代碼表中條目的數據結構*/ typedef struct HuffCode_ { unsigned char used; unsigned char code; unsigned char size; }HuffCode; /*定義LZ77令牌成員所須要的位數*/
#define LZ77_TYPE_BITS   1
#define LZ77_WINOFF_BITS 12
#define LZ77_BUFLEN_BITS 5
#define LZ77_NEXT_BITS   8

/*定義滑動窗口的大小和LZ77的超前緩衝區. 每一個都必須小於或等於2,分別提升到LZ77_WINOFF_BITS和LZ77_BUFLEN_BITS。 */
#define LZ77_WINDOW_SIZE  4096
#define LZ77_BUFFER_SIZE  32 

/*定義LZ77短語標記的位數*/
#define LZ77_SYMBOL_BITS  (LZ77_TYPE_BITS + LZ77_WINOFF_BITS + LZ77_NEXT_BITS + LZ77_BUFLEN_BITS)

/*函數接口*/
int huffman_compress(const unsigned char *original, unsigned char **compressed, int size); int huffman_uncompress(const unsigned char *compressed, unsigned char **original); int lz77_compress(const unsigned char *original, unsigned char **compressed, int size); int lz77_uncompress(const unsigned char *compressed, unsigned char **original); #endif // COMPRESS_H

位操做的描述

在壓縮和解壓縮數據時,經常要在小於一個字節的數量級上進行數據操做。因此,在學習各類數據壓縮的方法以前,必須熟悉一些對數據位進行的操做,這很是重要。本節展現的方法包含了對任意位的緩衝區的操做。固然,這裏介紹的位操做只是一部分,只是定義瞭如今數據壓縮和後續的數據加密中所要用到的操做。code

位操做的接口定義

bit_getblog


int bit_get (const unsigned char *bits, int pos);索引

返回值:相應位所處的狀態:0或1。

描述:獲取緩衝區bits中處於位置pos的位的狀態。緩衝區最左邊的位置爲0。返回的狀態值爲0或1。

複雜度:O(1)

bit_set


void bit_set (unsigned char *bits, int pos, int state);

返回值:無

描述:設置緩衝區bits中處於位置pos的位的狀態(根據state值來設置)。緩衝區最左邊的位設置爲0。狀態值必須爲0或1。

複雜度:O(1)

bit_xor


void bit_xor (const unsigned char *bits1, const unsigned char *bits2, unsigned char *bitsx, int size);

返回值:

描述:按位計算兩個緩衝區bits1和bits2的異或值,其中每一個緩衝區包含size個位,而後將結果返回bitsx中。異或的過程是將兩個二進制操做數進行運算,若是操做數據處於位置i的兩位相同,獲得0;若是處於位置i的兩位不一樣,則返回1。例如:11010 異或 01011 = 10001。bitsx所須要的存儲空間由函數調用者來管理。

複雜度:O(B),其中B爲每一個緩衝區中位的個數。

bit_rot_left


void bit_rot_left (unsigned char *bits, int size, int count);

返回值:無

描述:輪轉緩衝區bits(含size位),將位值向左移動count位。此操做完成後,處於最左端的count位移動到緩衝區的最右端,並且其餘的位也相應的輪轉。

複雜度:O(nB),其中B爲每一個緩衝區中位的個數,n爲要輪轉到左邊的位數。

位操做的實現與分析

每一個位操做均可操做緩衝區中的數據,緩衝區由無符號字符做爲指針來指定。該指針指向足夠多的字節來表示緩衝區中的位數。若是緩衝區中的位數不是8的倍數,那麼說明最後一個字節的某些位沒有使用。

bit_get

bit_get操做獲取緩衝區中一個位的狀態。要作到這一點,首先要肯定位所在的字節,而後經過一個掩碼從字節中獲取相應的位。掩碼中設置爲1的位是將要從字節中讀出的位,用一個循環操做將此位移動到適當的位置,經過索引bits中相應的字節,並應用調用後的掩碼,能夠獲取所需的位。

bit_get的時間複雜度爲O(1)。這是由於獲取緩衝區中的位的狀態所進行的操做都可以在固定的時間內完成。

bit_set

bit_set 操做設置緩衝區中的一個位的狀態。此操做與bit_get的工做方式類似,只是它是利用掩碼設置指定的位的狀態,而bit_get是獲取指定位的狀態。

bit_set的時間複雜度爲O(1)。這是由於獲取緩衝區中位的狀態所進行的全部操做都可以在固定的時間內完成。

bit_xor

bit_xor對兩個緩衝區bits1和bits2進行按位異或運算,並將計算的結果放到緩衝區bitsx中。要作到這一點,將bits1中第i個位置的位與bits2中第i個位置的位進行比較,若是位值相同,將第i個位置的位置爲0;不然,將第i個位置的位置爲1。這個過程持續下去直到緩衝區中size指定的每一個位都計算完成。

bit_xor的時間複雜度爲O(B),其中B是每一個緩衝區中的位數。這是由於此操做要在每一個位上循環迭代一次。

bit_rot_left

bit_rot_left將緩衝區指定數量的位向左輪轉。首先,保存最左端字節的最左端的位,而後向左一位一位地移動每一個字節的位值。在移動字節的過程當中,將前一個字節最右邊的位移動到當前字節的最左邊。當處理到最後一個字節時,將其最右邊的位移動到首字節的最高位上。這個過程一直持續下去直到全部的位都輪轉到位。

bit_rot_left的時間複雜度爲O(nB),其中n爲要向左輪轉的位的個數,B是緩衝區中位的個數。這是由於,對於每次輪轉,要進行(B/8)+1次移動。

 示例:位操做的實現

/*bit.c 位操做的實現*/ #include <stdlib.h> #include "bit.h"

/*bit_get 獲取緩衝區bits中處於pos位的狀態*/
int bit_get(const unsigned char *bits, int pos) { unsigned char mask; int i; /*設置掩碼*/ mask = ox80; for(i=0; i<(pos % 8); i++) mask = mask >> 1; /*用位與運算獲取對應的位*/
    return (((mask & bits[(int)(pos / 8)]) == mask)? 1:0) } /*bit_set 設置緩衝區bits中位於pos位的狀態*/
void bit_set(unsigned char *bits, int pos, int state) { unsigned char mask; int i; /*設置掩碼*/ mask = ox80; for(i=0; i<(pos % 8); i++) mask=mask>>1; /*依據state設置位*/
    if(state) bits[pos/8] = bits[pos/8] | mask; else bits[pos/8] = bits[pos/8] & (~mask); return; } /*bit_xor 按位異或運算*/
void bit_xor(const unsigned char *bits1,const unsigned char *bits2,unsigned char *bitsx,int size) { int i; /*計算兩個緩衝區的按位異或*/
    for(i=0;i<size;i++) { if(bit_get(bits1,i) != bit_get(bits2,i)) bit_set(bitsx,i,1); else bit_set(bitsx,i,0); } return; } /*bit_rot_left 輪轉緩衝區bits(含size位),將位值向左移count位*/
void bit_rot_left(unsigned char *bits,int size,int count) { int fbit,lbit,i,j; /*將緩衝區向左輪轉指定位數*/
    if(size > 0) { for(j=0; j<count; j++) { for(i=0; i<=((size-1)/8); i++) { /*得到要從當前字節偏移的位*/ lbit = bit_get(&bit[i],0); if(i==0) { /*保存要從首字節移動到後面的位*/ fbit = lbit; } else { /*將前一字節最右邊的位設置爲當前字節最左邊的位*/ bit_set(&bits[i-1],7,lbit); } /*將當前字節向左移動*/ bits[i] = bits[i] << 1; } /*將緩衝區最右邊的位設置爲從第一個字節偏移的位*/ bit_set(bits,size-1,fbit); } } return; }
相關文章
相關標籤/搜索