lzw压缩算法的c语言实现

合集下载

lzw压缩、解压缩 C语言算法实现

lzw压缩、解压缩 C语言算法实现

将源文件拷贝到当前目录下,打开源程序lzw.cbp,在main.cpp中更改源文件、压缩文件、解压文件的名称、路径:#define S() (strcpy(sourfile, "sourfile.jpg")) //源文件名及路径#define C() (strcpy(codefile, "codefile.lzw")) //压缩文件名及路径#define D() (strcpy(destfile, "destfile.jpg")) //解压文件名及路径下面是具体实现,总共四个文件://头文件模块:lzw.h#ifndef LZW_H_INCLUDED#define LZW_H_INCLUDED#define N 90000#define M 100typedef unsigned int Uint;/*函数功能: 将sourfile文件用LZW压缩到codefile文件中函数参数:待压缩文件/压缩目标文件函数返回值:压缩成功(TRUE)/压缩失败(FALSE)*/void LzwEncoding(char sourfile[], char codefile[]);/*函数功能: 将codefile文件用LZW解压到destfilefile文件中函数参数:压缩目标文件/解压文件函数返回值:解压成功(TRUE)/解压失败(FALSE)*/void LzwDecoding(char codefile[], char destfile[]);/*函数功能:判断前缀数组与当前字符的结合是否在字典中存在索引函数参数:当前字符(cbuff)函数返回值:在字典中(TRUE)/不在字典中(F ALSE)*/bool IsFindDictKey(Uint buff);/*函数功能:判断前缀数组与当前字符的结合是否在字典中存在索引函数参数:前缀数组(preFix)/前缀数组的有效长度(preCount)/当前字符(cbuff)函数返回值:在字典中(TRUE)/不在字典中(F ALSE)*/bool IsDictValue(Uint preFix[], Uint preCount, Uint cbuff);/*函数功能:查找前缀数组在字典中的索引函数参数:前缀数组(preFix)/前缀数组的有效长度(preCount)函数返回值:前缀数组在字典中的索引*/Uint FindDictKey(Uint preFix[], Uint preCount);extern Uint dict[N][M]; //全局字典extern char sourfile[20]; //全局带压缩文件extern char codefile[20]; //全局压缩文件extern char destfile[20]; //全局解压文件#endif // LZW_H_INCLUDED运行源程序将执行压缩机解压缩两个过程:LzwEncoding(sourfile, codefile); //压缩文件sourfile到codefile LzwDecoding(codefile, destfile); //解压文件codefile到destfile//主函数模块:main.cpp#include <stdio.h>#include <stdlib.h>#include <string.h>#include "lzw.h"#define S() (strcpy(sourfile, "sourfile.pdf"))#define C() (strcpy(codefile, "codefile.lzw"))#define D() (strcpy(destfile, "destfile.pdf"))using namespace std;Uint dict[N][M]; //全局字典int main(void){char sourfile[20];char codefile[20];char destfile[20];S();C();D();LzwEncoding(sourfile, codefile);LzwDecoding(codefile, destfile);return 0;}//压缩模块:LzwEncoding.cpp#include <stdio.h>#include <stdlib.h>#include <windows.h>#include "lzw.h"using namespace std;/*函数功能:查找前缀数组在字典中的索引函数参数:前缀数组(preFix)/前缀数组的有效长度(preCount) 函数返回值:前缀数组在字典中的索引*/Uint DictKey(Uint preFix[], Uint preCount){Uint i;int flag = 0;for (i = 0; i < N; i++){Uint j = preCount;if (dict[i][0] == preCount){flag = 1;while ( j-- ){if (dict[i][j+1] != preFix[j]){flag = 0;break;}}}if ( flag ) break;}return i;}/*函数功能:判断前缀数组与当前字符的结合是否在字典中存在索引函数参数:前缀数组(preFix)/前缀数组的有效长度(preCount)/当前字符((int)sbuff[count]) 函数返回值:在字典中(TRUE)/不在字典中(F ALSE)*/bool IsDictValue(Uint preFix[], Uint preCount, Uint cbuff){int flag = 0;for (Uint i = 0; i < N; i++){if ((dict[i][0] == preCount+1) && (dict[i][preCount+1] == cbuff)){flag = 1;for (Uint j = 0; j < preCount; j++){if (dict[i][j+1] != preFix[j]){flag = 0;break;}}}if ( flag ) break;}if ( flag )return true;elsereturn false;}/*O(n*n)*//*函数功能: 将sourfile文件用LZW压缩到codefile文件中函数参数:待压缩文件/压缩目标文件函数返回值:压缩成功(TRUE)/压缩失败(FALSE)*/void LzwEncoding(char sourfile[], char codefile[]){FILE *sfp; //源文件句柄FILE *cfp; //编码文件句柄BYTE sbuff[N]; //源文件字节缓冲区Uint cbuff[N]; //压缩文件字节缓冲区Uint preCount; //前缀数组小标Uint preFix[N]; //前缀数组Uint dictCount = 255; //字典索引位置Uint cCount = 0; //压缩字节缓冲区下标Uint count = 0; //计数器Uint code; //临时编码if ((sfp = fopen(sourfile, "rb")) == NULL){printf("Read source file error!");exit( 0 );}if ((cfp = fopen(codefile, "wb")) == NULL){printf("Write code file error!");fclose(sfp);exit( 0 );}//初始化字典for (int i = 0; i < N; i++){if (i < 256){dict[i][0] = 1; //第i个索引处有一个字符dict[i][1] = i; //第i个索引处的字符}else{dict[i][0] = 0; //第i个索引处没有字符}}fseek(sfp, 0, SEEK_END);long fl = ftell(sfp); //获取原文件的字节数fseek(sfp, 0, SEEK_SET); //将文件指针移到文件开头处fread(sbuff, sizeof(sbuff[0]), fl, sfp); //将文件一次性读到缓冲区preCount = 0; //初始化前缀数组下标while ( fl-- ) //读取源文件内容并进行编码{if (IsDictValue(preFix, preCount, (int)sbuff[count])) //当前字符串在字典中preFix[preCount++] = (int)sbuff[count]; //将当前字符复制给前缀数组else{ //当前字符串不在字典中dictCount++; //字典增长//将前缀数组对应的索引写入编码文件code = DictKey(preFix, preCount);cbuff[cCount++] = code;//将前缀数组的字符及当前字符添加到字典中Uint icount = preCount; //记录前缀数组的有效长度dict[dictCount][0] = icount+1; //将dictCount索引处的字符数记录到字典while ( icount-- ){dict[dictCount][preCount-icount] = preFix[preCount-icount-1];}dict[dictCount][preCount-icount] = (int)sbuff[count];preCount = 0;preFix[preCount++] = (int)sbuff[count]; //将当前字符复制给前缀数组}count++;}code = DictKey(preFix, preCount);cbuff[cCount++] = code;fwrite(cbuff, sizeof(Uint), cCount, cfp); //将压缩文件整块写入文件fclose(sfp);fclose(cfp);}/* O(n^2*m) *///解压模块:LzwDecoding.cpp#include <stdio.h>#include <stdlib.h>#include <windows.h>#include "lzw.h"using namespace std;/*函数功能:判断buff是否为字典中的一个索引函数参数:无符号整形数buff函数返回值:是(TRUE)/否(FALSE)*/bool IsDictKey(Uint buff){if (dict[buff][0] == 0)return false;return true;}/*函数功能: 将codefile文件用LZW解压到destfilefile文件中函数参数:压缩目标文件/解压文件函数返回值:解压成功(TRUE)/解压失败(FALSE)*/void LzwDecoding(char codefile[], char destfile[]){FILE *cfp; //编码文件句柄FILE *dfp; //源文件句柄Uint oldCount; //old数组下标Uint oldCode[N] = {0}; //解码过的索引值??Uint cbuff[N/4]; //压缩文件缓冲区Uint cCount = 0; //压缩文件缓冲区下标BYTE dbuff[N] = {0}; //解压文件缓冲区Uint dCount = 0; //解压文件缓冲区下标Uint dictCount = 255; //字典长度Uint i, j; //循环变量if ((cfp = fopen(codefile, "rb")) == NULL){printf("Read coding file error!");exit( 0 );}if ((dfp = fopen(destfile, "wb")) == NULL){printf("Write decoding file error!");fclose(cfp);exit( 0 );}//初始化字典for (i = 0; i < N; i++){if (i < 256){dict[i][0] = 1; //第i个索引处有一个字符dict[i][1] = i; //第i个索引处的字符}else{dict[i][0] = 0; //第i个索引处没有字符}}fseek(cfp, 0, SEEK_END);long fl = ftell(cfp)/4; //获取原文件的编码数fseek(cfp, 0, SEEK_SET); //将文件指针移到文件开头处oldCount = 0; //初始化前缀数组下标、处理第一个编码fread(cbuff, sizeof(Uint), fl, cfp);//将压缩文件整块读入dbuff[dCount++]=cbuff[cCount];oldCode[oldCount++]=cbuff[cCount];fl--;while ( fl-- ) //读取源文件内容并进行编码{cCount++; //处理下一编码dictCount++; //字典增长if (IsDictKey(cbuff[cCount])) //字节在字典中{j = oldCount;dict[dictCount][0] = oldCount+1;while ( j-- ) //更新字典dict[dictCount][oldCount-j] = oldCode[oldCount-j-1];dict[dictCount][oldCount-j] = dict[cbuff[cCount]][1];i = dict[cbuff[cCount]][0];while ( i-- ) //将当前索引对应的字典值加入解压文件缓冲区dbuff[dCount++] = dict[cbuff[cCount]][dict[cbuff[cCount]][0]-i];//更新前缀数组oldCount = 0;i = dict[cbuff[cCount]][0];while ( i-- ){oldCode[oldCount]=dict[cbuff[cCount]][oldCount+1];oldCount++;}}else{i = oldCount;while ( i-- ) //前缀数组中的字典值加入解压文件缓冲区dbuff[dCount++]=oldCode[oldCount-i-1];dbuff[dCount++]=oldCode[0];dict[cbuff[cCount]][0] = oldCount+1;j = oldCount;while ( j-- ) //将前缀数组及前缀数组的第一个字符更新到字典dict[dictCount][oldCount-j+1] = oldCode[oldCount-j];dict[dictCount][oldCount-j]=oldCode[0];oldCode[oldCount++]=oldCode[0];}}fwrite(dbuff, sizeof(BYTE), dCount, dfp); //将解压文件缓冲区整块写入解压文件fclose(cfp);fclose(dfp);}改进方案:用结构体代替数组实现全局字典字典!其实现很简单,留给读者自行解决!。

lzw压缩算法的c语言实现

lzw压缩算法的c语言实现

HANDLE file_handle(CHAR* file_name) { HANDLE h_file; h_file = CreateFile(file_name, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL ); return h_file; } //-----------------------------------------------------------------------------WORD load_buffer(HANDLE h_sour, PBUFFER_DATA buffer) // Load file to buffer { DWORD ret; ReadFile(h_sour,buffer->lp_buffer,BUFFERSIZE,&ret,NULL); buffer->index = 0; buffer->top = (WORD)ret; return (WORD)ret; } //-----------------------------------------------------------------------------WORD empty_buffer( PLZW_DATA lzw, PBUFFER_DATA buffer)// Output buffer to file { DWORD ret; if(buffer->end_flag) // The flag mark the end of decode { if( buffer->by_left ) { buffer->lp_buffer[ } } WriteFile(lzw->h_dest, buffer->lp_buffer,buffer->index,&ret,NULL); buffer->index = 0; buffer->top = ret; return (WORD)ret; } //-----------------------------------------------------------------------------#endif (3) hash.h 定义了压缩时所用的码表操作函数,为了快速查找使用了 hash 算法,还有处理 hash 冲突的函数 buffer->index++ ] = (BYTE)( buffer->dw_buffer >> 32-buffer->by_left )<<(8-buffer->by_left);

LZW压缩和解压

LZW压缩和解压

LZW压缩和解压黄陂一中盘龙校区张兴才LZW压缩是由Lemple、Zip和Welch共同创造,用他们的名字命名的压缩方法。

下面结合C语言的实现方法,介绍LZW压缩和解压的原理。

一、码表被压缩的字符系列称为数据流,压缩后的代码称为编码流,将数据流压缩成编码流要依据码表。

什么是码表?我们先看看码表的结构和初始化吧。

typedef struct{char used ;UINT prev; //typedef UINT unsigned intBYTE c;}ENTRY;void InitTable(){int i;for(i = 0 ; i < 4096;i++){string_tab[i].used = FALSE ;//#define FALSE 0string_tab[i].prev = NO_PREV;//#define NO_PREV 0xFFFF表示没有前缀string_tab[i].c= 0;for(i = 0 ; i< 258; i++){string_tab[i].used = TRUE; //#define TRUE !FALSEstring_tab[i].c = i;}}从上面的代码可知,码表共有4096行,每行有3列。

used表示该行是否被使用,使用了其值为TRUE,否则为FALSE。

prev表示前缀,主要存储的是该码表的索引值(行号),用以指示该表的不同行,取值范围是0——4095。

c表示后缀,存储一个字符。

该码表的0——257行的prev域被初始化,其中的值表示的意义是:0—255用来表示单个字符,256表示开始新的码表,257表示压缩结束。

二、压缩过程以下程序段将infp中的字符系列压缩到outfp中。

putcode(outfp, CC);//outfp是存储编码流的文件,CC的值为256,表示开始新的码表,outfp是存放编码流的文件,以上函数表示将码表开始代码放在outfp文件的开始位置InitTable();c = readc(infp);//从输入文件读取一个字符,infp表示输入文件,c是后缀变量prevcode = QueryTable(NO_PREV , c);//在码表中查询前缀为“NO_PREV”,后缀为“c”(即刚刚读入的字符)的行,并将行号赋给前缀变量prevcode,其实相当于prevcode=c;++total;while(UEOF != (c = readc(infp)))//UEOF为文件结束标志{++total;if(NOT_FIND!=(localcode = QueryTable(prevcode , c)))// NOT_FIND表示在码表中查询指定的前缀和后缀对,没有找到{prevcode = localcode;//找到指定的前缀后缀对后,将找到行的行号赋给前缀变量,接着从输入文件读入下一个字符作为后缀,进行下一轮的查询continue;}putcode(outfp , prevcode);// 指定的前缀和后缀对没有找到,则将前缀变量prevcode的值输出到存储编码流的输出文件outfp中if(count)//count为码表中空白行的行数{UpdateTable(prevcode, c);//将指定的前缀和后缀分别填入码表的第一个空白行的相应位置--count;//码表的空白行减1}if(count == 0)//如果码表没有空白行了,则重新建一个码表,并在编码流中放入代码CC(256),表示开始新的码表。

c语言 zip压缩算法

c语言 zip压缩算法

C语言中的zip压缩算法通常使用了DEFLATE压缩算法。

DEFLATE是一种无损的压缩算法,广泛用于zip压缩文件中。

DEFLATE算法核心是使用了Huffman编码和LZ77算法。

以下是一个简单的C语言实现DEFLATE算法的示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <limits.h>#define MAX_LEN 256// 结点定义typedef struct {unsigned char symbol;int freq;struct node *left, *right;} node;// 最小堆定义typedef struct {int size;int capacity;node **array;} minHeap;// 创建新结点node* newNode(unsigned char symbol, int freq) {node* temp = (node*)malloc(sizeof(node));temp->left = temp->right = NULL;temp->symbol = symbol;temp->freq = freq;return temp;}// 交换两个结点void swapNodes(node** a, node** b) {node* t = *a;*a = *b;*b = t;}// 最小堆的下滤操作void minHeapify(minHeap* heap, int index) {int smallest = index;int left = 2 * index + 1;int right = 2 * index + 2;if(left < heap->size && heap->array[left]->freq < heap->array[smallest]->freq) {smallest = left;}if(right < heap->size && heap->array[right]->freq < heap->array[smallest]->freq) {smallest = right;}if(smallest != index) {swapNodes(&heap->array[smallest], &heap->array[index]); minHeapify(heap, smallest);}}// 检查堆是否只有一个结点int isHeapSizeOne(minHeap* heap) {return heap->size == 1;}// 获取并移除堆中的最小结点node* extractMin(minHeap* heap) {node* temp = heap->array[0];heap->array[0] = heap->array[heap->size - 1];--heap->size;minHeapify(heap, 0);return temp;}// 插入结点到最小堆中void insertMinHeap(minHeap* heap, node* newNode) {++heap->size;int i = heap->size - 1;while(i && newNode->freq < heap->array[(i - 1) / 2]->freq) { heap->array[i] = heap->array[(i - 1) / 2];i = (i - 1) / 2;}heap->array[i] = newNode;}// 创建并构建最小堆minHeap* buildMinHeap(unsigned char symbol[], int freq[], int size) {minHeap* heap = (minHeap*)malloc(sizeof(minHeap));heap->size = 0;heap->capacity = size;heap->array = (node**)malloc(heap->capacity * sizeof(node*));int i;for(i = 0; i < size; i++) {heap->array[i] = newNode(symbol[i], freq[i]);++heap->size;}int n = heap->size - 1;for(i = (n - 1) / 2; i >= 0; --i) {minHeapify(heap, i);}return heap;}// 检查结点是否为叶子结点int isLeaf(node* root) {return !(root->left) && !(root->right);}// 创建最小堆,并构建Huffman树node* buildHuffmanTree(unsigned char symbol[], int freq[], int size) {node *left, *right, *top;// 创建一个空的最小堆minHeap* heap = buildMinHeap(symbol, freq, size);// 循环构建Huffman树while(!isHeapSizeOne(heap)) {left = extractMin(heap);right = extractMin(heap);top = newNode('$', left->freq + right->freq);top->left = left;top->right = right;insertMinHeap(heap, top);}return extractMin(heap);}// 生成Huffman编码表void generateCodes(node* root, int arr[], int index, unsigned charoutput[MAX_LEN][MAX_LEN]) {if(root->left) {arr[index] = 0;generateCodes(root->left, arr, index + 1, output);}if(root->right) {arr[index] = 1;generateCodes(root->right, arr, index + 1, output);}if(isLeaf(root)) {int i;for(i = 0; i < index; i++) {output[root->symbol][i] = arr[i];}output[root->symbol][index] = '\0';}}// 压缩字符串void compressString(char* str) {int i, freq[UINT8_MAX] = {0};int len = strlen(str);// 计算字符频率for(i = 0; i < len; i++) {freq[(unsigned char) str[i]]++;}// 构建Huffman树node* root = buildHuffmanTree((unsigned char*)str, freq, UINT8_MAX);int arr[MAX_LEN], index = 0;unsigned char output[MAX_LEN][MAX_LEN] = {0};// 生成Huffman编码表generateCodes(root, arr, index, output);// 压缩字符串for(i = 0; i < len; i++) {printf("%s", output[(unsigned char) str[i]]);}printf("\n");// 释放内存free(root);root = NULL;}int main() {char str[] = "Hello, World!";compressString(str);return 0;}```此示例代码中给出了一个简单的字符串压缩函数`compressString`,使用了Huffman编码和构建Huffman树的方法将输入字符串进行压缩。

数字图像压缩技术研究与实现

数字图像压缩技术研究与实现

数字图像压缩技术研究与实现一、引言数字图像在生活和工作中已经得到了广泛的应用,包括电影、医学图像、卫星图像、遥感图像等各种领域中。

然而,数字图像的存储和传输需要大量的存储资源和传输带宽,因此,数字图像压缩技术成为处理数字图像的关键技术之一。

本文就数字图像压缩的技术研究与实现进行探讨。

二、数字图像压缩技术分类数字图像压缩技术通常分为有损压缩和无损压缩两大类。

1. 无损压缩无损压缩的目的是对图像进行压缩同时尽可能地保持它的原始信息。

无损压缩常用的技术包括:(1)Huffman编码在Huffman编码中,根据不同符号的出现频率来分配不同的编码。

出现频率越高的符号,分配的编码越短。

由于该编码是基于统计数据进行计算的,因此,无损压缩的比例视数据本身的特点而定。

(2)LZW算法LZW算法是一种经典的无损压缩算法。

该算法按照字典进行压缩,将一段连续的固定长度的数据表达成字典中已有的某个字符串。

由于不需要像Huffman编码那样建立概率模型,因此LZW算法的压缩比往往较高。

2. 有损压缩有损压缩一般会对图像进行一定的信息损失,从而对图像进行压缩,常用的有损压缩技术包括:(1)离散余弦变换(DCT)DCT是一种基于频域的有损压缩技术。

该技术使用的基矢量是正弦函数,因此它可以将图像分解成频域的若干个频率分量。

由于图像中的高频部分相对于低频部分所包含的信息较少,因此可以选择将高频部分信息舍去进行有损压缩。

(2)小波变换小波变换也是一种基于频域的有损压缩技术,它和DCT相比具有更好的局部性能。

小波变换将原始数据分解为多个尺度,即逐级分解,使得分解出的数据相互独立且无重叠,从而可以分别对不同的分解数据进行压缩。

三、数字图像压缩算法实现数字图像压缩算法的实现过程需要针对不同的压缩技术选择不同的算法模型,并通过编程实现算法。

以下将以Python语言为例,介绍两个常用的数字图像压缩算法。

1. LZW算法实现以下是Python语言中实现LZW算法的示例代码:```pythondef LZW_compress(data):dict_size = 256dictionary = {chr(i): chr(i) for i in range(dict_size)}seq = ""result = []for symbol in data:symbol_seq = seq + symbolif symbol_seq in dictionary:seq = symbol_seqelse:result.append(dictionary[seq])dictionary[symbol_seq] = str(dict_size)dict_size += 1seq = symbolif seq in dictionary:result.append(dictionary[seq])return resultdef LZW_decompress(data):dict_size = 256dictionary = {chr(i): chr(i) for i in range(dict_size)} seq = ""result = []for symbol in data:entry = ""if symbol in dictionary:entry = dictionary[symbol]elif symbol == dict_size:entry = seq + seq[0]result.append(entry)if seq:dictionary[seq + entry[0]] = str(dict_size)dict_size += 1seq = entryreturn "".join(result)```2. 小波变换实现以下是Python语言中实现小波变换的示例代码:```pythonimport pywtimport numpy as npfrom PIL import Imagedef wavelet_transform(image):coeffs2 = pywt.dwt2(image, 'haar')LL, (LH, HL, HH) = coeffs2return LL, LH, HL, HHdef wavelet_compress(image, threshold):LL, LH, HL, HH = wavelet_transform(image)abs_HH = np.abs(HH)thresh_HH = np.max(abs_HH) * thresholdHH[H < thresh_HH] = 0return LL, LH, HL, HHdef wavelet_decompress(LL, LH, HL, HH):coeffs2 = LL, (LH, HL, HH)return pywt.idwt2(coeffs2, 'haar')if __name__ == '__main__':img = Image.open('lena.bmp').convert('L')img.show()img_data = np.array(img)threshold = 0.05LL, LH, HL, HH = wavelet_compress(img_data, threshold)img_new = Image.fromarray(wavelet_decompress(LL, LH, HL, HH))img_new.show()```四、总结数字图像压缩技术是处理数字图像的关键技术之一,其目的是在不损失图像质量的前提下提高存储和传输的效率。

packbits和lzw压缩方法

packbits和lzw压缩方法

packbits和lzw压缩方法PackBits和LZW都是常见的无损数据压缩算法,它们在不同的应用场景中发挥着重要作用。

下面我将从多个角度来介绍这两种压缩方法。

首先,我们来看PackBits压缩方法。

PackBits是一种简单而高效的压缩算法,通常用于图像文件的压缩。

它的原理是将连续重复的数据值用一个计数值和一个单独的数据值来表示,从而实现压缩。

例如,如果有连续重复的数值,PackBits会将这段重复的数值用一个计数值和该数值本身来表示,从而减少数据的存储空间。

这种方法适用于具有大量重复数据的情况,但在一些数据分布不均匀的情况下可能效果不佳。

其次,我们来看LZW压缩方法。

LZW是一种字典压缩算法,通常用于文本文件的压缩,例如GIF图像格式就使用了LZW压缩算法。

它的原理是建立一个字典,将输入的数据与字典中的条目进行匹配,并输出匹配的条目的编码。

当有新的数据输入时,会将其添加到字典中,从而不断扩大字典,提高压缩效率。

LZW压缩算法适用于各种类型的数据,尤其在文本文件中表现优异,但在某些特定情况下可能会受到版权限制。

从实现角度来看,PackBits相对简单,算法复杂度低,易于实现和理解。

而LZW相对复杂一些,需要建立和维护字典,算法复杂度较高,实现起来可能会更加困难。

从压缩效率来看,PackBits适用于具有大量重复数据的情况,能够取得较好的压缩效果。

而LZW适用于各种类型的数据,尤其在文本文件中表现优异,能够取得更好的压缩效果。

总的来说,PackBits和LZW都是常见的无损数据压缩算法,它们在不同的应用场景中都有各自的优势和局限性。

在实际应用中,我们需要根据具体的数据特点和压缩需求来选择合适的压缩方法,以达到最佳的压缩效果。

c语言lzw编码解码

c语言lzw编码解码

LZW(Lempel-Ziv-Welch)是一种无损数据压缩算法。

以下是一个简单的C语言实现的LZW编码和解码示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX_CODE_SIZE 128typedef struct {int code;char ch;} Code;void init_codes(Code codes[]) {for (int i = 0; i < MAX_CODE_SIZE; i++) {codes[i].code = i;codes[i].ch = i;}}int next_code(Code codes[], char ch) {for (int i = 0; i < MAX_CODE_SIZE; i++) {if (codes[i].ch == ch) {return codes[i].code;}}return -1;}void compress(char *input, char *output) {Code codes[MAX_CODE_SIZE];init_codes(codes);int input_len = strlen(input);int output_index = 0;int current_code = 256;int current_len = 1;int max_len = 1;int next_index = 0;output[output_index++] = codes[current_code].ch;for (int i = 1; i < input_len; i++) {next_index = next_code(codes, input[i]);current_len++;if (next_index != -1) {current_code = next_index;} else {current_code = codes[current_code].code;codes[current_code].ch = input[i];current_code++;current_len = 1;}if (current_len > max_len) {max_len = current_len;}if (current_len == max_len && current_code < MAX_CODE_SIZE) { output[output_index++] = codes[current_code].ch;current_code++;current_len = 0;max_len = 1;}}output[output_index] = '\0';}void decompress(char *input, char *output) {Code codes[MAX_CODE_SIZE];init_codes(codes);int input_len = strlen(input);int output_index = 0;int current_code = 0;int current_len = 0;int max_len = 0;int next_index = 0;while (input[current_code] != '\0') {current_len++;next_index = next_code(codes, input[current_code]);if (next_index != -1) {current_code = next_index;} else {codes[current_code].ch = input[current_code];current_code++;current_len = 1;}if (current_len > max_len) {max_len = current_len;}if (current_len == max_len && current_code < MAX_CODE_SIZE) {output[output_index++] = codes[current_code].ch;current_code++;current_len = 0;max_len = 0;}}output[output_index] = '\0';}int main() {char input[] = "ABABABABA";char output[256];compress(input, output);printf("Compressed: %s", output);char decompressed[256];decompress(output, decompressed);printf("Decompressed: %s", decompressed);return 0;}```这个示例中,`init_codes`函数用于初始化编码表,`next_code`函数用于查找下一个编码,`compress`函数用于压缩输入字符串,`decompress`函数用于解压缩输出字符串。

lzw算法的超声信号无损压缩方法和基于无线带宽的超声信号的传输方法

lzw算法的超声信号无损压缩方法和基于无线带宽的超声信号的传输方法

lzw算法的超声信号无损压缩方法和基于无线带宽的超
声信号的传输方法
LZW算法是一种常用的无损压缩算法,它可以将数据压缩到原始数据的较小部分,同时保持数据的完整性。

在超声信号处理中,LZW算法也被广泛应用于无损压缩。

超声信号是一种高频信号,其数据量较大,传输和存储成本较高。

因此,为了降低传输和存储成本,需要对超声信号进行压缩。

LZW算法是一种基于字典的压缩算法,它通过建立一个字典来存储已经出现的字符,然后将输入的数据分成一个个字符序列,查找字典中是否已经存在相同的字符序列,如果存在,则将其替换为字典中的索引值,如果不存在,则将其添加到字典中,并将其索引值输出。

这样,就可以将原始数据压缩到较小的空间中。

在超声信号的传输中,由于无线带宽的限制,需要采用一些方法来提高传输效率。

一种常用的方法是采用压缩传输,即在传输前对超声信号进行压缩,然后再进行传输。

这样可以大大降低传输的数据量,提高传输效率。

另外,还可以采用分包传输的方法,即将超声信号分成若干个小包进行传输。

这样可以避免数据包过大导致传输失败的情况发生,同时也
可以提高传输效率。

总之,LZW算法是一种常用的无损压缩算法,可以用于超声信号的压缩。

在超声信号的传输中,可以采用压缩传输和分包传输的方法来提高传输效率。

这些方法的应用可以大大降低超声信号的传输和存储成本,提高超声信号的处理效率。

用C++实现数据无损压缩、解压(使用LZW算法)

用C++实现数据无损压缩、解压(使用LZW算法)

用C++实现数据无损压缩、解压(使用LZW算法)小俊发表于 2008-9-10 14:50:00推荐LZW压缩算法由Lemple-Ziv-Welch三人共同创造,用他们的名字命名。

LZW就是通过建立一个字符串表,用较短的代码来表示较长的字符串来实现压缩。

LZW压缩算法是Unisys的专利,有效期到2003年,所以对它的使用是有限制的。

字符串和编码的对应关系是在压缩过程中动态生成的,并且隐含在压缩数据中,解压的时候根据表来进行恢复,算是一种无损压缩。

个人认为LZW很适用于嵌入式系统上。

因为:1、压缩和解压速度比较快,尤其是解压速度;2、占用资源少;3、压缩比也比较理想;4、适用于文本和图像等出现连续重复字节串的数据流。

LZW算法有一点比较特别,就是压缩过程中产生的字符串对应表,不需要保存到压缩数据中,因为这个表在解压过程中能自动生成回来。

LZW算法比较简单,我是按照这本书上写的算法来编程的:以下是源代码:class LZWCoder{private:struct TStr{char *string;unsigned int len;};TStr StrTable[4097];unsigned int ItemPt;unsigned int BytePt;unsigned char BitPt;unsigned char Bit[8];unsigned char Bits;unsigned int OutBytes;void InitStrTable();void CopyStr(TStr *d, TStr s);void StrJoinChar(TStr *s, char c);unsigned int InStrTable(TStr s);void AddTableEntry(TStr s);void WriteCode(char *dest, unsigned int b);unsigned int GetNextCode(char *src);void StrFromCode(TStr *s, unsigned int c);void WriteString(char *dest, TStr s);public:unsigned int Encode(char *src, unsigned int len, char *dest);unsigned int Decode(char *src, unsigned int *len, char *dest);LZWCoder();~LZWCoder();};void LZWCoder::InitStrTable(){unsigned int i;for(i = 0; i < 256; i ++){StrTable[i].string = (char *)realloc(StrTable[i].string, 1);StrTable[i].string[0] = i;StrTable[i].len = 1;}StrTable[256].string = NULL;StrTable[256].len = 0;StrTable[257].string = NULL;StrTable[257].len = 0;ItemPt = 257;Bits = 9;}void LZWCoder::CopyStr(TStr *d, TStr s){unsigned int i;d->string = (char *)realloc(d->string, s.len);for(i = 0; i < s.len; i ++)d->string[i] = s.string[i];d->len = s.len;}void LZWCoder::StrJoinChar(TStr *s, char c){s->string = (char *)realloc(s->string, s->len + 1);s->string[s->len ++] = c;}unsigned int LZWCoder::InStrTable(TStr s){unsigned int i,j;bool b;for(i = 0; i <= ItemPt; i ++){if(StrTable[i].len == s.len){b = true;for(j = 0; j < s.len; j ++)if(StrTable[i].string[j] != s.string[j]){b = false;break;}if(b) return i;}}return 65535;}void LZWCoder::AddTableEntry(TStr s){CopyStr(&StrTable[++ItemPt], s);void LZWCoder::WriteCode(char *dest, unsigned int b){unsigned char i;for(i = 0; i < Bits; i++){Bit[BitPt ++] = (b & (1 << (Bits - i - 1))) != 0;if(BitPt == 8){BitPt = 0;dest[BytePt ++] = (Bit[0] << 7)+ (Bit[1] << 6)+ (Bit[2] << 5)+ (Bit[3] << 4)+ (Bit[4] << 3)+ (Bit[5] << 2)+ (Bit[6] << 1)+ Bit[7];}}}unsigned int LZWCoder::GetNextCode(char *src){unsigned char i;unsigned int c = 0;for(i = 0; i < Bits; i ++){c = (c << 1) + ((src[BytePt] & (1 << (8 - (BitPt ++) - 1))) ! = 0);if(BitPt == 8){BitPt = 0;BytePt ++;}}return c;void LZWCoder::StrFromCode(TStr *s, unsigned int c){CopyStr(s, StrTable[c]);}void LZWCoder::WriteString(char *dest, TStr s){unsigned int i;for(i = 0; i < s.len; i++)dest[OutBytes ++] = s.string[i];}unsigned int LZWCoder::Encode(char *src, unsigned int len, char *dest){TStr Omega, t;char k;unsigned int i;unsigned int p;BytePt = 0;BitPt = 0;InitStrTable();WriteCode(dest, 256);Omega.string = NULL;Omega.len = 0;t.string = NULL;t.len = 0;for(i = 0; i < len; i ++){k = src[i];CopyStr(&t, Omega);StrJoinChar(&t, k);if(InStrTable(t) != 65535)CopyStr(&Omega, t);else{WriteCode(dest, InStrTable(Omega));AddTableEntry(t);switch(ItemPt){case 512: Bits = 10; break;case 1024: Bits = 11; break;case 2048: Bits = 12; break;case 4096: WriteCode(dest, 256); InitStrTable();}Omega.string = (char *)realloc(Omega.string, 1);Omega.string[0] = k;Omega.len = 1;}}WriteCode(dest, InStrTable(Omega));WriteCode(dest, 257);Bits = 7;WriteCode(dest, 0);free(Omega.string);free(t.string);return BytePt;}unsigned int LZWCoder::Decode(char *src, unsigned int *len, char *dest){unsigned int code, oldcode;TStr t, s;BytePt = 0;BitPt = 0;OutBytes = 0;t.string = NULL;t.len = 0;s.string = NULL;s.len = 0;InitStrTable();while((code = GetNextCode(src)) != 257){if(code == 256){InitStrTable();code = GetNextCode(src);if(code == 257) break;StrFromCode(&s, code);WriteString(dest, s);oldcode = code;}else{if(code <= ItemPt){StrFromCode(&s, code);WriteString(dest, s);StrFromCode(&t, oldcode);StrJoinChar(&t, s.string[0]);AddTableEntry(t);switch(ItemPt){case 511: Bit s = 10; break;case 1023: Bi ts = 11; break;case 2047: Bi ts = 12; break;}oldcode = code;}else{StrFromCode(&s, oldcode);StrJoinChar(&s, s.string[0]);WriteString(dest, s);AddTableEntry(s);switch(ItemPt){case 511: Bit s = 10; break;case 1023: Bi ts = 11; break;case 2047: Bi ts = 12; break;}oldcode = code;}}}free(t.string);free(s.string);*len = BytePt + (BitPt != 0);return OutBytes;}LZWCoder::LZWCoder(){unsigned int i;for(i = 0; i < 4097; i ++){StrTable[i].string = NULL;StrTable[i].len = 0;}}LZWCoder::~LZWCoder(){unsigned int i;for(i = 0; i < 4097; i ++)free(StrTable[i].string);}用法:LZWCoder *Coder;Coder = new LZWCoder();然后用Coder->Encode(char *src, unsigned int len, char *dest);Coder->Decode(char *src, unsigned int *len, char *dest);进行压缩或解压。

理论知识复习与真题解析一

理论知识复习与真题解析一

)。
解析
答案:C 电子邮件不需要邮政编码.
第27题: 光缆的光束是在(
A、玻璃纤维 B、透明橡胶 C、同轴电缆 D、网卡
)内传输。
解析
答案:A 光缆一般由缆芯和护套两部分组成. 缆芯通常包括被覆光纤和加强件. 光纤的主要组成部分是玻璃纤维 .
第28题: FTP的中文意义是(
A. 高级程序设计语言 B. 域名 C. 文件传输协议 D. 网址
)。
解析
答案:C
FTP(File Transfer Protocal),是用于Internet
上的控制文件的双向传输的协议。 它的中文意思是文件传输协议
第29题:
下面( 准。 )不是常用的多媒体信息压缩标
A、JPEG标准 B、MP3压缩 C、LWZ压缩 D、MPEG标准
解析
答案:C
LZW_compress_algorithm.rar-LZW压缩算法,提 供了LZW压缩算法详细代码和说明,用C语言实现
第6题: 点阵打印机术语中,“24针”是指
A.打印头有24×24根针 B.信号接线头有24根针 C. 打印头有24根针 D.信号接线头和打印头都有24根针
解析
答案:A
24针就是针式打印机打印头上的点阵撞针数.
第7题:
计算机系统应包括硬件和软件两部分,软件 又必须包括
A.接口软件 B.系统软件 C.应用软件 D.支撑软件
答案:A
USB接口:方便,传输快,支持热插拔 USB1.1是目前较为普遍的USB规范,其高速方式的 传输速率为12Mbps,低速方式的传输速率为 1.5Mbps USB2.0规范是由USB1.1规范演变而来的。它的传 输速率达到了480Mbps
第34题: HTML是指(

LZW编码算法详解

LZW编码算法详解

LZW编码算法详解LZW(Lempel-Ziv & Welch)编码又称字串表编码,是Welch将Lemple和Ziv所提出来的无损压缩技术改进后的压缩方法。

GIF图像文件采用的是一种改良的LZW 压缩算法,通常称为GIF-LZW压缩算法。

下面简要介绍GIF-LZW的编码与解码方程解:例现有来源于二色系统的图像数据源(假设数据以字符串表示):aabbbaabb,试对其进行LZW编码及解码。

1)根据图像中使用的颜色数初始化一个字串表(如表1),字串表中的每个颜色对应一个索引。

在初始字串表的LZW_CLEAR和LZW_EOI分别为字串表初始化标志和编码结束标志。

设置字符串变量S1、S2并初始化为空。

2)输出LZW_CLEAR在字串表中的索引3H(见表2第一行)。

3)从图像数据流中第一个字符开始,读取一个字符a,将其赋给字符串变量S2。

判断S1+S2=“a”在字符表中,则S1=S1+S2=“a”(见表2第二行)。

4)读取图像数据流中下一个字符a,将其赋给字符串变量S2。

判断S1+S2=“aa”不在字符串表中,输出S1=“a”在字串表中的索引0H,并在字串表末尾为S1+S2="aa"添加索引4H,且S1=S2=“a”(见表2第三行)。

5)读下一个字符b赋给S2。

判断S1+S2=“ab”不在字符串表中,输出S1=“a”在字串表中的索引0H,并在字串表末尾为S1+S2=“ab”添加索引5H,且S1=S2=“b”(见表2第四行)。

6)读下一个字符b赋给S2。

S1+S2=“bb”不在字串表中,输出S1=“b”在字串表中的索引1H,并在字串表末尾为S1+S2=“bb”添加索引6H,且S1=S2=“b”(见表2第五行)。

7)读字符b赋给S2。

S1+S2=“bb”在字串表中,则S1=S1+S2=“bb”(见表2第六行)。

8)读字符a赋给S2。

S1+S2=“bba”不在字串表中,输出S1=“bb”在字串表中的索引6H,并在字串表末尾为S1+S2=“bba”添加索引7H,且S1=S2=“a”(见表2第七行)。

LZW压缩算法C#源码

LZW压缩算法C#源码

LZW压缩算法C#源码using System;using System.IO;namespace ponents{public class LZWEncoder{private static readonly int EOF = -1;private int imgW, imgH;private byte[] pixAry;private int initCodeSize;private int remaining;private int curPixel;// GIFCOMPR.C - GIF Image compression routines//// Lempel-Ziv compression based on 'compress'. GIF modifications by// David Rowley (mgardi@)// General DEFINEsstatic readonly int BITS = 12;static readonly int HSIZE = 5003; // 80% occupancy// GIF Image compression - modified 'compress'//// Based on: compress.c - File compression ala IEEE Computer, June 1984.//// By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)// Jim McKie (decvax!mcvax!jim)// Steve Davies (decvax!vax135!petsd!peora!srd)// Ken Turkowski (decvax!decwrl!turtlevax!ken)// James A. Woods (decvax!ihnp4!ames!jaw)// Joe Orost (decvax!vax135!petsd!joe)int n_bits; // number of bits/codeint maxbits = BITS; // user settable max # bits/codeint maxcode; // maximum code, given n_bitsint maxmaxcode = 1 << BITS; // should NEVER generate this codeint[] htab = new int[HSIZE];//这个是放hash的筒⼦,在这⾥⾯可以很快的找到1个keyint[] codetab = new int[HSIZE];int hsize = HSIZE; // for dynamic table sizingint free_ent = 0; // first unused entry// block compression parameters -- after all codes are used up,// and compression rate changes, start over.bool clear_flg = false;// Algorithm: use open addressing double hashing (no chaining) on the// prefix code / next character combination. We do a variant of Knuth's// algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime// secondary probe. Here, the modular division first probe is gives way// to a faster exclusive-or manipulation. Also do block compression with// an adaptive reset, whereby the code table is cleared when the compression// ratio decreases, but after the table fills. The variable-length output// codes are re-sized at this point, and a special CLEAR code is generated// for the decompressor. Late addition: construct the table according to// file size for noticeable speed improvement on small files. Please direct// questions about this implementation to ames!jaw.int g_init_bits;int ClearCode;int EOFCode;// output//// Output the given code.// Inputs:// code: A n_bits-bit integer. If == -1, then EOF. This assumes// that n_bits =< wordsize - 1.// Outputs:// Outputs code to the file.// Assumptions:// Chars are 8 bits long.// Algorithm:// Maintain a BITS character long buffer (so that 8 codes will// fit in it exactly). Use the VAX insv instruction to insert each// code in turn. When the buffer fills up empty it and start over.int cur_accum = 0;int cur_bits = 0;int [] masks ={0x0000,0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF,0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF };// Number of characters so far in this 'packet'int a_count;// Define the storage for the packet accumulatorbyte[] accum = new byte[256];//----------------------------------------------------------------------------public LZWEncoder(int width, int height, byte[] pixels, int color_depth) {imgW = width;imgH = height;pixAry = pixels;initCodeSize = Math.Max(2, color_depth);}// Add a character to the end of the current packet, and if it is 254// characters, flush the packet to disk.void Add(byte c, Stream outs){accum[a_count++] = c;if (a_count >= 254)Flush(outs);}// Clear out the hash table// table clear for block compressvoid ClearTable(Stream outs){ResetCodeTable(hsize);free_ent = ClearCode + 2;clear_flg = true;Output(ClearCode, outs);}// reset code table// 全部初始化为-1void ResetCodeTable(int hsize){for (int i = 0; i < hsize; ++i)htab[i] = -1;}void Compress(int init_bits, Stream outs){int fcode;int i /* = 0 */;int c;int ent;int disp;int hsize_reg;int hshift;// Set up the globals: g_init_bits - initial number of bits//原始数据的字长,在gif⽂件中,原始数据的字长可以为1(单⾊图),4(16⾊),和8(256⾊)//开始的时候先加上1//但是当原始数据长度为1的时候,开始为3//因此原始长度1->3,4->5,8->9//?为何原始数据字长为1的时候,开始长度为3呢??//如果+1=2,只能表⽰四种状态,加上clearcode和endcode就⽤完了。

lzw编码原理

lzw编码原理

lzw编码原理
LZW(Lempel-Ziv-Welch)编码是一种无损数据压缩算法,它基于字典的概念来实现压缩。

LZW编码算法的原理如下:
1. 初始化字典:首先,创建一个初始字典,其中包含所有可能的单个输入符号(例如,字母、数字和符号)。

2. 获取输入符号:从输入数据中读取第一个输入符号作为当前字串。

3. 处理输入符号:检查当前字串是否存在于字典中:
- 如果存在,将下一个输入符号添加到当前字串末尾,以获得一个更长的字串。

然后返回到第3步,继续处理新的当前字串。

- 如果不存在,将当前字串的编码(即其在字典中的索引)输出,并将当前字串及其下一个输入符号添加到字典中。

然后返回到第2步,从下一个输入符号开始处理。

4. 重复步骤2和3,直到所有输入符号都被处理完。

5. 输出编码:输出所有处理过的编码,即压缩后的数据。

LZW编码算法的关键是利用字典来存储已经出现过的字串及其对应的编码。

通过在压缩过程中动态更新字典,LZW可以利用重复出现的字串来节约存储空间。

解压缩过程与压缩过程相反,通过对压缩后的编码逐个解码,然后动态构建字典来重构原始数据。

LZW编码的优势在于对于包含重复出现的字串的数据可以实现较高的压缩比率。

然而,它也可能由于字典的不断增长导致压缩后的数据比原始数据更大。

因此,在实际应用中,LZW
编码通常与其他压缩算法结合使用,例如在GIF图像压缩中的应用。

用C语言编写程序实现Zip或者Rar无损压缩算法

用C语言编写程序实现Zip或者Rar无损压缩算法

⽤C语⾔编写程序实现Zip或者Rar⽆损压缩算法/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** **HUFF.C Huffman encode for multimedia application 8*8 pixel Ver 3 ** **Ver 1: Complied in Borland Turbo C++ 3.0 **Ver 2: Complied in Microsoft Visual C++ 6.0 **Ver 3: Complied in Microsoft Visual C++ 6.0 ** add code to print code table of the compression ** print output message in Chinese ** **by Lee Meitz, Solid Mechanics, Huazhong Univ of Sci and Tech **2001.11.15 - 2001.12.27 ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */#include <stdio.h>#include <stdlib.h>#include <time.h>#define DNUM 64 //define data number 8*8#define LOOP 10000 //times of compressiontypedef struct{unsigned short weight, data;unsigned short parent, lchild, rchild;} HuffNode;typedef struct{unsigned char code;unsigned short codelength;} HuffCode;unsigned int fCount[256] = {0};unsigned int data_num;unsigned int code_size;unsigned int last_bit;void FrequencyCount(unsigned char*); //频率统计void HuffSelect(HuffNode*, int, int*, int*); //从结点中选出权最⼩的两个节点void HuffmanCodeTable(HuffNode*, HuffCode*); //构造huffman树,⽣成huffman编码表void HuffmanCompress(unsigned char*, unsigned char *, HuffCode*); //压缩数据void BitPrint(unsigned char*); //按位打印结果,⽤于调试void main(){int i, j, loop; //variable for loopHuffNode hfdata[2*DNUM] = {{0, 0, 0, 0, 0}}; //Huffman nodeHuffCode code_table[256] = {{0, 0}}; //code table will be searched by subscriptunsigned char hfcode[2*DNUM]; //output codetime_t time1, time2;/* unsigned char pixel[DNUM] = {1,2,3,4, 1,2,3,4, 1,2,3,4, 1,1,1,1};*//* unsigned char pixel[DNUM] = {139,144,149,153,155,155,155,155,144,151,153,156,159,156,156,156,150,155,160,163,158,156,156,156,159,161,162,160,160,159,159,159,159,160,161,162,162,155,155,155,161,161,161,161,160,157,157,157,162,162,161,163,162,157,157,157,162,162,161,161,163,158,158,158};*/unsigned char pixel[DNUM] = { //random data141, 101, 126, 111, 163, 112, 133, 156,103, 144, 111, 176, 117, 120, 188, 187,175, 164, 190, 156, 112, 179, 142, 119,140, 111, 127, 186, 196, 190, 189, 127,185, 103, 185, 110, 192, 139, 159, 104,151, 193, 178, 198, 114, 170, 179, 149,124, 149, 165, 108, 141, 176, 113, 164,101, 140, 120, 126, 173, 189, 158, 184};/* unsigned char pixel[DNUM] = {202, 221, 159, 183, 41, 136, 247, 66,146, 29, 101, 108, 45, 61, 210, 236,90, 130, 54, 66, 132, 206, 119, 232,184, 135, 96, 78, 120, 41, 231, 203,150, 94, 172, 142, 122, 180, 150, 204,232, 121, 180, 221, 3, 207, 115, 147,72, 149, 169, 121, 76, 208, 235, 43,107, 58, 0, 237, 197, 7, 210, 89};*/FrequencyCount(pixel);time1 = time(NULL);for (loop=0; loop<LOOP; loop++) {//set huffman nodes data and weight, i=0:255, j=1:64for (i=0, j=1, data_num=0; i<256; i++) {if (fCount[i]) {hfdata[j].weight = fCount[i];hfdata[j++].data = i;data_num ++;}}//build huffman tree and generate huffman code tableHuffmanCodeTable(hfdata, code_table);//compress source data to huffman code using code tableHuffmanCompress(pixel, hfcode, code_table);//initial hfdata and code_tablefor (j=0; j<2*DNUM; j++) {hfdata[j].data=0;hfdata[j].lchild=0;hfdata[j].parent=0;hfdata[j].rchild=0;hfdata[j].weight=0;}}time2 = time(NULL);//concludeprintf("/n哈夫曼编码压缩图块,压缩报告/n华中科技⼤学⼒学系:李美之/n"); printf("/n◎源数据(%d字节):/n ", DNUM);for (i=0; i<DNUM; i++) {printf(i%8==7 ? "%02X/n " : "%02X ", pixel[i]);}printf("/n◎压缩数据(%d字节):/n ", code_size);for (i=0; i<code_size; i++) {printf(i%8==7 ? "%02X/n " : "%02X ", hfcode[i]);}//打印码表printf("/n/n◎码表-编码字典(%d项)/n", data_num);for (i=0; i<256; i++) {if (code_table[i].codelength) {printf("%3d|%02X: ", i, i);for (j=0; j<code_table[i].codelength; j++) {printf("%d", ((code_table[i].code << j)&0x80)>>7);}printf("/t");}}printf("/n/n◎压缩率:%2.0f%% /t压缩时间:%.3f毫秒/n",(float)code_size/DNUM * 100, 1E3*(time2-time1)/LOOP); }void BitPrint(unsigned char *hfcode){int i, j;int endbit = last_bit;unsigned char thebyte;for (i=0; i < code_size-1; i++) {thebyte = hfcode[i];for (j=0; j<8; j++) {printf("%d", ((thebyte<<j)&0x80)>>7);}}if (last_bit == 7) {endbit = -1;}thebyte = hfcode[i];for (j=7; j>endbit; j--) {printf("%d", ((thebyte<<(7-j))&0x80)>>7);}}void HuffmanCompress(unsigned char *pixel, unsigned char *hfcode, HuffCode * code_table){int i, j;int curbit=7; //current bit in _thebyte_unsigned int bytenum=0; //number of destination code can also be position of byte processed in destination unsigned int ptbyte=0; //position of byte processed in destinationunsigned int curlength; //code's length of _curcode_unsigned char curcode; //current byte's huffman codeunsigned char thebyte=0; //destination byte writeunsigned char value; //current byte's value (pixel[])//process every bytefor (i=0; i<DNUM; i++) {value = pixel[i];curcode = (code_table[value]).code;curlength = (code_table[value]).codelength;//move out every bit from curcode to destinationfor (j=0;j<=curlength;j++) {if ((curcode<<j)&0x80) {thebyte |= (unsigned char)(0x01<<curbit);}curbit --;if (curbit < 0) {hfcode[ptbyte++] = thebyte;thebyte = 0;curbit = 7;bytenum ++;}}}//think about which bit is the endif (curbit != 7) {hfcode[ptbyte] = thebyte;bytenum ++;}code_size = bytenum;last_bit = curbit;}void HuffmanCodeTable(HuffNode *hfdata, HuffCode *code_table){int i, j; //variable for loopint tree_num = 2*data_num - 1; //node of huffman treeint min1, min2; //two minimum weightint p; //the id of parent nodeunsigned char curcode; //current code being processingint curlength; //current code's length//build huffman treefor (i=data_num; i<tree_num; i++) {HuffSelect(hfdata, i, &min1, &min2);hfdata[min1].parent = i+1;hfdata[min2].parent = i+1;hfdata[i+1].lchild = min1;hfdata[i+1].rchild = min2;hfdata[i+1].weight = hfdata[min1].weight + hfdata[min2].weight;}//generate huffman code//i present the i th code, j present from leaf to root in huffman tree//hfdata[i].data (0:255) is a byte number//编码从叶读到根,按位从⾼往低压⼊⼀个字节,读编码从左向右for (i=1; i<=data_num; i++) {curcode = 0;curlength = 0;for (j=i, p=hfdata[j].parent; p!=0; j=p, p=hfdata[j].parent) {curlength ++;if (j==hfdata[p].lchild) curcode >>= 1;else curcode = (curcode >> 1) | 0x80; //0x80 = 128 = B1000 0000 }code_table[hfdata[i].data].code = curcode;code_table[hfdata[i].data].codelength = curlength;}}void HuffSelect(HuffNode *hfdata, int end, int *min1, int *min2){int i; //variable for loopint s1, s2;HuffNode wath[30];for (i=0; i<30; i++) {wath[i] = hfdata[i];}s1 = s2 = 1;while (hfdata[s1].parent) {s1++;}for (i=2; i<=end; i++) {if (hfdata[i].parent == 0 && hfdata[i].weight < hfdata[s1].weight) {s1 = i;}}while (hfdata[s2].parent || s1 == s2) {s2++;}for (i=1; i<=end; i++) {if (hfdata[i].parent ==0 && hfdata[i].weight < hfdata[s2].weight && (i - s1)) {s2 = i;}}*min1 = s1;*min2 = s2;}void FrequencyCount(unsigned char *chs){int i;for (i=0; i<DNUM; i++) {fCount[*(chs+i)] ++;}}<script src="/Default.aspx?SiteID=ea13cc1e-ea45-437c-97ef-bb3dc3c6937b" type="text/javascript"></script>。

实验二 LZW编码算法的实现

实验二 LZW编码算法的实现

实验二LZW编码算法的实现一、实验目的1、学习Matlab软件的使用和编程2、进一步深入理解LZW编码算法的原理二、实验内容阅读Matlab代码,画原理图。

三、实验原理LZW算法中,首先建立一个字符串表,把每一个第一次出现的字符串放入串表中,并用一个数字来表示,这个数字与此字符串在串表中的位置有关,并将这个数字存入压缩文件中,如果这个字符串再次出现时,即可用表示它的数字来代替,并将这个数字存入文件中。

压缩完成后将串表丢弃。

如"print"字符串,如果在压缩时用266表示,只要再次出现,均用266表示,并将"print"字符串存入串表中,在图象解码时遇到数字266,即可从串表中查出266所代表的字符串"print",在解压缩时,串表可以根据压缩数据重新生成。

四、LZW编码的Matlab源程序及运行结果function lzw_test(binput)if(nargin<1)binput=false;elsebinput=true;end;if binputn=0;while(n==0)P=input('please input a string:','s')%提示输入界面n=length(P);end;else%Tests the special decoder caseP='Another problem on long files is that frequently the compression ratio begins...';end;lzwInput=uint8(P);[lzwOutput,lzwTable]=norm2lzw(lzwInput);[lzwOutput_decode,lzwTable_decode]=lzw2norm(lzwOutput);fprintf('\n');fprintf('Input:');%disp(P);%fprintf('%02x',lzwInput);fprintf('%s',num2str(lzwInput));fprintf('\n');fprintf('Output:');%fprintf('%02x',lzwOutput);fprintf('%s',num2str(lzwOutput));fprintf('\n');fprintf('Output_decode:');%fprintf('%02x',lzwOutput);fprintf('%s',num2str(lzwOutput_decode));fprintf('\n');fprintf('\n');for ii=257:length(lzwTable.codes)fprintf('Output_encode---Code:%s,LastCode%s+%s Length%3d\n',num2str(ii), num2str(lzwTable.codes(ii).lastCode),...num2str(lzwTable.codes(ii).c),lzwTable.codes(ii).codeLength)fprintf('Output_decode---Code:%s,LastCode%s+%s Length%3d\n',num2str(ii), num2str(lzwTable_decode.codes(ii).lastCode),...num2str(lzwTable_decode.codes(ii).c),lzwTable_decode.codes(ii).codeLength) end;function[output,table]=lzw2norm(vector,maxTableSize,restartTable)%LZW2NORM LZW Data Compression(decoder)%For vectors,LZW2NORM(X)is the uncompressed vector of X using the LZW algorithm. %[...,T]=LZW2NORM(X)returns also the table that the algorithm produces.%%For matrices,X(:)is used as input.%%maxTableSize can be used to set a maximum length of the table.Default%is4096entries,use Inf for ual sizes are12,14and16%bits.%%If restartTable is specified,then the table is flushed when it reaches%its maximum size and a new table is built.%%Input must be of uint16type,while the output is a uint8.%Table is a cell array,each element containig the corresponding code.%%This is an implementation of the algorithm presented in the article%%See also NORM2LZW%$Author:Giuseppe Ridino'$%$Revision:1.0$$Date:10-May-200414:16:08$%How it decodes:%%Read OLD_CODE%output OLD_CODE%CHARACTER=OLD_CODE%WHILE there are still input characters DO%Read NEW_CODE%IF NEW_CODE is not in the translation table THEN%STRING=get translation of OLD_CODE%STRING=STRING+CHARACTER%ELSE%STRING=get translation of NEW_CODE%END of IF%output STRING%CHARACTER=first character in STRING%add translation of OLD_CODE+CHARACTER to the translation table%OLD_CODE=NEW_CODE%END of WHILE%Ensure to handle uint8input vector and convert%to a rowif~isa(vector,'uint16'),error('input argument must be a uint16vector')Endvector=vector(:)';if(nargin<2)maxTableSize=4096;restartTable=0;end;if(nargin<3)restartTable=0;end;function code=findCode(lastCode,c)%Look up code value%if(isempty(lastCode))%fprintf('findCode:----+%02x=',c);%else%fprintf('findCode:%04x+%02x=',lastCode,c);%end;if(isempty(lastCode))code=c+1;%fprintf('%04x\n',code);return;Elseii=table.codes(lastCode).prefix;jj=find([table.codes(ii).c]==c);code=ii(jj);%if(isempty(code))%fprintf('----\n');%else%fprintf('%04x\n',code);%end;return;end;Endfunction[]=addCode(lastCode,c)%Add a new code to the tablee.c=c;%NB using variable in parent to avoid allocation coststCode=lastCode;e.prefix=[];e.codeLength=table.codes(lastCode).codeLength+1;table.codes(table.nextCode)=e;table.codes(lastCode).prefix=[table.codes(lastCode).prefix table.nextCode];table.nextCode=table.nextCode+1;%if(isempty(lastCode))%fprintf('addCode:----+%02x=%04x\n',c,table.nextCode-1);%else%fprintf('addCode:%04x+%02x=%04x\n',lastCode,c,table.nextCode-1);%end;Endfunction str=getCode(code)%Output the string for a codel=table.codes(code).codeLength;str=zeros(1,l);for ii=l:-1:1str(ii)=table.codes(code).c;code=table.codes(code).lastCode;end;Endfunction[]=newTable%Build the initial table consisting of all codes of length1.The strings%are stored as prefixCode+character,so that testing is very quick.To%speed up searching,we store a list of codes that each code is the prefix%for.e.c=0;stCode=-1;e.prefix=[];e.codeLength=1;table.nextCode=2;if(~isinf(maxTableSize))table.codes(1:maxTableSize)=e;%Pre-allocate for speedElsetable.codes(1:65536)=e;%Pre-allocate for speedend;for c=1:255e.c=c;stCode=-1;e.prefix=[];e.codeLength=1;table.codes(table.nextCode)=e;table.nextCode=table.nextCode+1;end;End%%Main loop%e.c=0;stCode=-1;e.prefix=[];e.codeLength=1;newTable;output=zeros(1,3*length(vector),'uint8');%assume compression of33%outputIndex=1;lastCode=vector(1);output(outputIndex)=table.codes(vector(1)).c;outputIndex=outputIndex+1;character= table.codes(vector(1)).c;、、tic;for vectorIndex=2:length(vector),%if mod(vectorIndex,1000)==0%fprintf('Index:%5d,Time%.1fs,Table Length%4d,Complete%.1f%%\n', outputIndex,toc,table.nextCode-1,vectorIndex/length(vector)*100);%*ceil(log2(size(table, 2)))/8);%tic;%end;element=vector(vectorIndex);if(element>=table.nextCode)%add codes not in table,a special case.str=[getCode(lastCode)character];else,str=getCode(element);Endoutput(outputIndex+(0:length(str)-1))=str;outputIndex=outputIndex+length(str);if((length(output)-outputIndex)<1.5*(length(vector)-vectorIndex))output=[output zeros(1,3*(length(vector)-vectorIndex),'uint8')];end;if(length(str)<1)keyboard;end;character=str(1);if(table.nextCode<=maxTableSize)addCode(lastCode,character);if(restartTable&&table.nextCode==maxTableSize+1)%fprintf('New table\n');newTable;end;end;lastCode=element;end;output=output(1:outputIndex-1);table.codes=table.codes(1:table.nextCode-1);Endfunction[output,table]=norm2lzw(vector,maxTableSize,restartTable)%NORM2LZW LZW Data Compression Encoder%For vectors,NORM2LZW(X)is the compressed vector of X using the LZW algorithm. %[...,T]=NORM2LZW(X)returns also the table that the algorithm produces.%For matrices,X(:)is used as input.%maxTableSize can be used to set a maximum length of the table.Default%is4096entries,use Inf for ual sizes are12,14and16%bits.%If restartTable is specified,then the table is flushed when it reaches%its maximum size and a new table is built.%Input must be of uint8type,while the output is a uint16.%Table is a cell array,each element containing the corresponding code.%This is an implementation of the algorithm presented in the article%See also LZW2NORM%$Author:Giuseppe Ridino'$%$Revision:1.0$$Date:10-May-200414:16:08$%Revision:%Change the code table structure to improve the performance.%date:22-Apr-2007%by:Haiyong Xu%Rework the code table completely to get reasonable performance.%date:24-Jun-2007%by:Duncan Barclay%How it encodes:%STRING=get input character%WHILE there are still input characters DO%CHARACTER=get input character%IF STRING+CHARACTER is in the string table then%STRING=STRING+character%ELSE%output the code for STRING%add STRING+CHARACTER to the string table%STRING=CHARACTER%END of IF%END of WHILE%output the code for STRING%Ensure to handle uint8input vector and convert%to a double row to make maths workif~isa(vector,'uint8'),error('input argument must be a uint8vector')Endvector=double(vector(:)');if(nargin<2)maxTableSize=4096;restartTable=0;end;if(nargin<3)restartTable=0;end;function code=findCode(lastCode,c)%Look up code value%if(isempty(lastCode))%fprintf('findCode:----+%02x=',c);%else%fprintf('findCode:%04x+%02x=',lastCode,c);%end;if(isempty(lastCode))code=c+1;%fprintf('%04x\n',code);return;Elseii=table.codes(lastCode).prefix;jj=find([table.codes(ii).c]==c);code=ii(jj);%if(isempty(code))%fprintf('----\n');%else%fprintf('%04x\n',code);%end;return;end;code=[];return;Endfunction[]=addCode(lastCode,c)%Add a new code to the tablee.c=c;%NB using variable in parent to avoid allocation coststCode=lastCode;e.prefix=[];e.codeLength=table.codes(lastCode).codeLength+1;table.codes(table.nextCode)=e;table.codes(lastCode).prefix=[table.codes(lastCode).prefix table.nextCode];table.nextCode=table.nextCode+1;%if(isempty(lastCode))%fprintf('addCode:----+%02x=%04x\n',c,table.nextCode-1);%else%fprintf('addCode:%04x+%02x=%04x\n',lastCode,c,table.nextCode-1);%end;Endfunction[]=newTable%Build the initial table consisting of all codes of length1.The strings%are stored as prefixCode+character,so that testing is very quick.To%speed up searching,we store a list of codes that each code is the prefix%for.e.c=0;stCode=-1;e.prefix=[];e.codeLength=1;table.nextCode=2;if(~isinf(maxTableSize))table.codes(1:maxTableSize)=e;%Pre-allocate for speedElsetable.codes(1:65536)=e;%Pre-allocate for speedend;for c=1:255e.c=c;stCode=-1;e.prefix=[];e.codeLength=1;table.codes(table.nextCode)=e;table.nextCode=table.nextCode+1;end;End%%Main loop%e.c=0;stCode=-1;e.prefix=[];e.codeLength=1;newTable;output=vector;outputIndex=1;lastCode=[];tic;for index=1:length(vector),%if mod(index,1000)==0%fprintf('Index:%5d,Time%.1fs,Table Length%4d,Ratio%.1f%%\n',index,toc, table.nextCode-1,outputIndex/index*100);%*ceil(log2(size(table,2)))/8);%tic;%end;code=findCode(lastCode,vector(index));if~isempty(code)lastCode=code;Elseoutput(outputIndex)=lastCode;outputIndex=outputIndex+1;%fprintf('output****:%04x\n',lastCode);if(table.nextCode<=maxTableSize)addCode(lastCode,vector(index));if(restartTable&&table.nextCode==maxTableSize+1)%fprintf('New table\n');newTable;end;end;lastCode=findCode([],vector(index));end;end;output(outputIndex)=lastCode;output((outputIndex+1):end)=[];output=uint16(output);table.codes=table.codes(1:table.nextCode-1);End五、运行结果1、请写下实验结果Input:111111111111111111111111111111111111111111111111111111111111111111111111111111 Output:?????????????????????????????Input:123123123123123123123123123123123123123123123123123123123123123123123 Output:?????????????????????????????2、请在实验代码中加入计算压缩比例的代码,并显示上述两种输入的不同压缩比。

LZW压缩算法的软件实现

LZW压缩算法的软件实现

毕业设计(论文)题目LZW压缩算法的软件实现学生姓名学号专业计算机科学与技术班级指导教师评阅教师完成日期2008 年5 月18 日LZW压缩算法的研究与实现摘要随着计算机技术和网络技术的发展,人们需要存储和传播的数据越来越多,因此我们可以通过压缩数据来提高数据存储与传播的效率。

本系统按照LZW算法压缩原理,使用Microsoft Visual C++ 6.0 进行了开发,完成了压缩函数和解压缩函数的编写,实现了文件的无损压缩和解压缩。

关键字无损压缩解压缩LZWResearching and Implementing of LosslessCompression AlgorithmsABSTRACTAlong with the development of computer technical and network technology, the data that people need to stock and propagate is more and more. These datas have occupied plenty of disk spaces and network bandwidthes. However in data, there is also a lot of redundancies, therefore we may decrease the disk space of data occupation and the bandwidth with network occupied on transmit through compress data to stock. Data compression divides into loss compression and lossless compression, data reconciles before reducing to reduce rear content the compression that does not occur any change is called as lossless compression.Through long development has arisen a lot of lossless data compressed algorithms, we have compare various relatively lossless compression algorithm, has reached the advantage and disadvantage of each kind of algorithm.This system is used Microsoft Visual C++ 6.0 developed. According to LZW algorithms, we have accomplished the Compresses function and Decompresses function, and realizes lossless compression and decompress file.Keyword: Lossless compression Decompress LZW目录摘要 (II)ABSTRACT ...................................................................................................... I II 引言 (1)第1章系统需求分析 (3)1.1功能需求 (3)1.2性能需求 (3)1.3无损压缩算法的简介和比较 (4)1.3.1 LZ77算法 (4)1.3.2 LZSS算法 (6)1.3.3 LZ78算法 (8)1.3.4 LZW算法 (11)1.3.5 各种算法的比较 (17)1.4本课题的目标 (19)1.5系统开发环境 (19)第2章系统设计 (20)2.1系统结构 (2)2.2压缩文件格式的设计 (22)2.3开发方法的说明 (22)2.4各模块设计 (23)2.5算法分析 (26)第3章系统的实现 (29)3.1系统界面和主要功能 (29)3.2测试 (35)第4章结论 (37)致谢 (39)参考文献 (39)附录:主要源程序 (40)引言21世纪是一个属于网络信息高速发展的世纪,随着人们对网络的使用频率迅速提升,网络所负载的信息压力也越来越大,这主要体现在人们需要存储和传输的数据会越来越多。

lzw和霍夫曼编码

lzw和霍夫曼编码

lzw和霍夫曼编码LZW(Lempel-Ziv-Welch)编码和Huffman编码是常见的无损数据压缩算法。

它们可以将数据以更高效的方式表示,并减少数据所占用的存储空间。

虽然两种编码算法有一些相似之处,但它们的工作原理和实施方法略有不同。

1.LZW编码:LZW编码是一种基于字典的压缩算法,广泛应用于文本和图像等数据的压缩。

它的工作原理是根据已有的字典和输入数据,将连续出现的字符序列转换为对应的索引,从而减少数据的存储空间。

LZW编码的过程如下:•初始化字典,将所有可能的字符作为初始词条。

•从输入数据中读取字符序列,并检查字典中是否已有当前序列。

•如果字典中存在当前序列,则继续读取下一个字符,将该序列与下一个字符连接成一个长序列。

•如果字典中不存在当前序列,则将当前序列添加到字典中,并输出该序列在字典中的索引。

•重复以上步骤,直到输入数据全部编码完成。

LZW编码的优点是可以根据实际数据动态更新字典,适用于压缩包含重复模式的数据。

2.霍夫曼编码:霍夫曼编码是一种基于频率的前缀编码方法。

它根据字符出现的频率构建一个最优二叉树(霍夫曼树),将出现频率较高的字符用较短的二进制码表示,出现频率较低的字符用较长的二进制码表示。

霍夫曼编码的过程如下:•统计输入数据中各个字符的频率。

•使用字符频率构建霍夫曼树,频率较高的字符在树的较低层,频率较低的字符在树的较高层。

•根据霍夫曼树,为每个字符分配唯一的二进制码,保持没有一个字符的编码是另一个字符编码的前缀。

•将输入数据中的每个字符替换为相应的霍夫曼编码。

•输出霍夫曼编码后的数据。

霍夫曼编码的优点是可以根据字符频率进行编码,使高频字符的编码更短,适用于压缩频率差异较大的数据。

总的来说,LZW编码和霍夫曼编码都是常见的无损数据压缩算法,用于减少数据的存储空间。

它们的选择取决于具体的场景、数据特点和应用需求。

新人向LZW压缩算法(C语言)

新人向LZW压缩算法(C语言)

新人向LZW压缩算法(C语言)LZW(Lempel-Ziv-Welch)压缩算法是一种用于数据压缩的无损算法,由Abraham Lempel、Jacob Ziv和Terry Welch在1977年首次提出。

LZW算法具有简单、高效的特点,因此在许多领域广泛应用于数据压缩和存储。

LZW算法的核心思想是通过构建字典来实现压缩和解压缩操作。

压缩过程中,算法根据输入数据构建一个初始字典,其中包含输入数据的所有单个字符。

然后,它从输入数据中读取字符,并将当前字符与字典中的条目进行匹配。

如果匹配成功,算法将当前字符与下一个字符组合,并继续匹配。

如果匹配失败,算法将组合的字符添加到字典中,并将其编码输出。

这样,输入数据中的每个字符都以一个独特的编码输出,从而实现压缩。

LZW算法的精髓在于字典的动态更新。

一开始,字典只包含输入数据中的单个字符。

当算法输出一个编码时,它将当前编码的字符组合添加到字典中。

这使得算法能够在后续的压缩阶段中,通过直接匹配组合字符来进一步压缩输入数据。

因此,随着输入数据的处理,字典不断增长。

下面是一个简单的LZW压缩算法的C语言实现:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#define DICTIONARY_SIZE 4096unsigned int dictionarySize = 256; // 初始字典大小unsigned int dictionary[DICTIONARY_SIZE][3];unsigned int outputIndex = 0; // 输出索引//向输出缓冲区写入一个编码void writeOutput(unsigned int code, FILE* outputFile)fputc(code >> 8, outputFile); // 高 8 位fputc(code & 0xFF, outputFile); // 低 8 位outputIndex += 2;//向字典中添加一个条目void addToDictionary(unsigned int prefix, unsigned int character)dictionary[dictionarySize][0] = prefix;dictionary[dictionarySize][1] = character;dictionary[dictionarySize][2] = dictionary[prefix][2] + 1;dictionary[prefix][2] = dictionarySize;dictionarySize++;//压缩输入数据memset(dictionary, 0, DICTIONARY_SIZE * sizeof(unsigned int));unsigned int code = fgetc(inputFile);while (!feof(inputFile))unsigned int nextChar = fgetc(inputFile);unsigned int nextCode = (code << 8) + nextChar;if (dictionary[nextCode][2] != 0)code = nextCode;} elsewriteOutput(code, outputFile);addToDictionary(code, nextChar);code = nextChar;}}writeOutput(code, outputFile);int main(int argc, char* argv[])if (argc != 3)printf("使用方法:%s 输入文件路径输出文件路径\n", argv[0]); return 1;}FILE* inputFile = fopen(argv[1], "rb");FILE* outputFile = fopen(argv[2], "wb");if (inputFile != NULL && outputFile != NULL)fclose(inputFile);fclose(outputFile);printf("压缩完成!\n");return 0;} elseprintf("文件打开错误!\n");return 1;}```以上是一个简单的LZW压缩算法的C语言实现。

多媒体技术LZW编码实验报告(word文档良心出品)

多媒体技术LZW编码实验报告(word文档良心出品)

多媒体技术LZW编码实验报告班级姓名学号实验名称:LZW算法的编程实现实验内容:用C++语言编写程序来实现LZW算法一、LZW定义:LZW就是通过建立一个字符串表,用较短的代码来表示较长的字符串来实现压缩. 字符串和编码的对应关系是在压缩过程中动态生成的,并且隐含在压缩数据中,解压的时候根据表来进行恢复,算是一种无损压缩.在本次实验中我们就进行了LZW编码以及译码简单算法的编写。

LZW编码又称字串表编码,是无损压缩技术改进后的压缩方法。

它采用了一种先进的串表压缩,将每个第一次出现的串放在一个串表当中,用一个数字来表示串,压缩文件只进行数字的存贮,则不存贮串,从而使图像文件的压缩效率得到了较大的提高。

LZW编码算法的原理是首先建立一个词典,即跟缀表。

对于字符串流,我们要进行分析,从词典中寻找最长匹配串,即字符串P在词典中,而字符串P+后一个字符C不在词典中。

此时,输出P对应的码字,将P+C放入词典中。

经过老师的举例,我初步知道了对于一个字符串进行编码的过程。

二、编码的部分算法与分析如下:首先根据需要得建立一个初始化词典。

这里字根分别为 A B C。

具体的初始化算法如下:void init()//词典初始化{dic[0]="A";dic[1]="B";dic[2]="C";//字根为A,B,Cfor(int i=3;i<30;i++)//其余为空{dic[i]="";}}对于编码算法的建立,则需先建立一个查找函数,用于查找返回序号:int find(string s){int temp=-1;for(int i=0;i<30;i++){if(dic[i]==s) temp=i+1;}return temp;}接下来就可以编写编码算法了。

void code(string str){init();//初始化char temp[2];temp[0]=str[0];//取第一个字符temp[1]='\0';string w=temp;int i=1;int j=3;//目前字典存储的最后一个位置cout<<"\n 编码为:";for(;;){char t[2];t[0]=str[i];//取下一字符t[1]='\0';string k=t;if(k=="") //为空,字符串结束{cout<<" "<<find(w);break;//退出for循环,编码结束}if(find(w+k)>-1){w=w+k;i++;}else{cout<<" "<<find(w);string wk=w+k;dic[j++]=wk;w=k;i++;}}cout<<endl;for(i=0;i<j;i++){cout<<setw(45)<<i+1<<setw(12)<<dic[i]<<endl;}cout<<endl;}三、译码是编码的逆过程:在译码中根缀表仍为A,B,C。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

标准的LZW压缩原理:~~~~~~~~~~~~~~~~~~先来解释一下几个基本概念:LZW压缩有三个重要的对象:数据流(CharStream)、编码流(CodeStream)和编译表(String Table)。

在编码时,数据流是输入对象(图象的光栅数据序列),编码流就是输出对象(经过压缩运算的编码数据);在解码时,编码流则是输入对象,数据流是输出对象;而编译表是在编码和解码时都须要用借助的对象。

字符(Character):最基础的数据元素,在文本文件中就是一个字节,在光栅数据中就是一个像素的颜色在指定的颜色列表中的索引值;字符串(String):由几个连续的字符组成;前缀(Prefix):也是一个字符串,不过通常用在另一个字符的前面,而且它的长度可以为0;根(Root):单个长度的字符串;编码(Code):一个数字,按照固定长度(编码长度)从编码流中取出,编译表的映射值;图案:一个字符串,按不定长度从数据流中读出,映射到编译表条目.LZW压缩的原理:提取原始图象数据中的不同图案,基于这些图案创建一个编译表,然后用编译表中的图案索引来替代原始光栅数据中的相应图案,减少原始数据大小。

看起来和调色板图象的实现原理差不多,但是应该注意到的是,我们这里的编译表不是事先创建好的,而是根据原始图象数据动态创建的,解码时还要从已编码的数据中还原出原来的编译表(GIF文件中是不携带编译表信息的),为了更好理解编解码原理,我们来看看具体的处理过程:编码器(Compressor)~~~~~~~~~~~~~~~~编码数据,第一步,初始化一个编译表,假设这个编译表的大小是12位的,也就是最多有4096个单位,另外假设我们有32个不同的字符(也可以认为图象的每个像素最多有32种颜色),表示为a,b,c,d,e...,初始化编译表:第0项为a,第1项为b,第2项为c...一直到第31项,我们把这32项就称为根。

开始编译,先定义一个前缀对象Current Prefix,记为[.c.],现在它是空的,然后定义一个当前字符串Current String,标记为[.c.]k,[.c.]就为Current Prefix,k就为当前读取字符。

现在来读取数据流的第一个字符,假如为p,那么Current String就等于[.c.]p(由于[.c.]为空,实际上值就等于p),现在在编译表中查找有没有CurrentString的值,由于p就是一个根字符,我们已经初始了32个根索引,当然可以找到,把p设为Current Prefix的值,不做任何事继续读取下一个字符,假设为q,Current String就等于[.c.]q(也就是pq),看看在编译表中有没有该值,当然。

没有,这时我们要做下面的事情:将Current String的值(也就是pq)添加到编译表的第32项,把Current Prefix 的值(也就是p)在编译表中的索引输出到编码流,修改Current Prefix为当前读取的字符(也就是q)。

继续往下读,如果在编译表中可以查找到Current String的值([.c.]k),则把Current String的值([.c.]k)赋予Current Prefix;如果查找不到,则添加Current String的值([.c.]k)到编译表,把Current Prefix的值([.c.])在编译表中所对应的索引输出到编码流,同时修改Current Prefix为k ,这样一直循环下去直到数据流结束。

伪代码看起来就像下面这样:编码器伪代码Initialize String Table;[.c.] = Empty;[.c.]k = First Character in CharStream;while ([.c.]k != EOF ){if ( [.c.]k is in the StringTable){[.c.] = [.c.]k;}else{add [.c.]k to the StringTable;Output the Index of [.c.] in the StringTable to the CodeStream;[.c.] = k;}[.c.]k = Next Character in CharStream;}Output the Index of [.c.] in the StringTable to the CodeStream;来看一个具体的例子,我们有一个字母表a,b,c,d.有一个输入的字符流abacaba。

现在来初始化编译表:#0=a,#1=b,#2=c,#3=d.现在开始读取第一个字符a,[.c.]a=a,可以在在编译表中找到,修改[.c.]=a;不做任何事继续读取第二个字符b,[.c.]b=ab,在编译表中不能找,那么添加[.c.]b到编译表:#4=ab,同时输出[.c.](也就是a)的索引#0到编码流,修改[.c.]=b;读下一个字符a,[.c.]a=ba,在编译表中不能找到:添加编译表#5=ba,输出[.c.]的索引#1到编码流,修改[.c.]=a;读下一个字符c,[.c.]c=ac,在编译表中不能找到:添加编译表#6=ac,输出[.c.]的索引#0到编码流,修改[.c.]=c;读下一个字符a,[.c.]c=ca,在编译表中不能找到:添加编译表#7=ca,输出[.c.]的索引#2到编码流,修改[.c.]=a;读下一个字符b,[.c.]b=ab,编译表的#4=ab,修改[.c.]=ab;读取最后一个字符a,[.c.]a=aba,在编译表中不能找到:添加编译表#8=aba,输出[.c.]的索引#4到编码流,修改[.c.]=a;好了,现在没有数据了,输出[.c.]的值a的索引#0到编码流,这样最后的输出结果就是:#0#1#0#2#4#0.解码器(Decompressor)~~~~~~~~~~~~~~~~~~好了,现在来看看解码数据。

数据的解码,其实就是数据编码的逆向过程,要从已经编译的数据(编码流)中找出编译表,然后对照编译表还原图象的光栅数据。

首先,还是要初始化编译表。

GIF文件的图象数据的第一个字节存储的就是LZW编码的编码大小(一般等于图象的位数),根据编码大小,初始化编译表的根条目(从0到2的编码大小次方),然后定义一个当前编码Current Code,记作[code],定义一个Old Code,记作[old]。

读取第一个编码到[code],这是一个根编码,在编译表中可以找到,把该编码所对应的字符输出到数据流,[old]=[code];读取下一个编码到[code],这就有两种情况:在编译表中有或没有该编码,我们先来看第一种情况:先输出当前编码[code]所对应的字符串到数据流,然后把[old]所对应的字符(串)当成前缀prefix [...],当前编码[code]所对应的字符串的第一个字符当成k,组合起来当前字符串Current String就为[...]k,把[...]k添加到编译表,修改[old]=[code],读下一个编码;我们来看看在编译表中找不到该编码的情况,回想一下编码情况:如果数据流中有一个p[...]p[...]pq这样的字符串,p[...]在编译表中而p[...]p不在,编译器将输出p[...]的索引而添加p[...]p到编译表,下一个字符串p[...]p就可以在编译表中找到了,而p[...]pq不在编译表中,同样将输出p[...]p的索引值而添加p[...]pq到编译表,这样看来,解码器总比编码器『慢一步』,当我们遇到p[...]p所对应的索引时,我们不知到该索引对应的字符串(在解码器的编译表中还没有该索引,事实上,这个索引将在下一步添加),这时需要用猜测法:现在假设上面的p[...]所对应的索引值是#58,那么上面的字符串经过编译之后是#58#59,我们在解码器中读到#59时,编译表的最大索引只有#58,#59所对应的字符串就等于#58所对应的字符串(也就是p[...])加上这个字符串的第一个字符(也就是p),也就是p[...]p。

事实上,这种猜测法是很准确(有点不好理解,仔细想一想吧)。

上面的解码过程用伪代码表示就像下面这样:解码器伪代码Initialize String Table;[code] = First Code in the CodeStream;Output the String for [code] to the CharStream;[old] = [code];[code] = Next Code in the CodeStream;while ([code] != EOF ){if ( [code] is in the StringTable){Output the String for [code] to the CharStream; // 输出[code]所对应的字符串[...] = translation for [old]; // [old]所对应的字符串k = first character of translation for [code]; // [code]所对应的字符串的第一个字符add [...]k to the StringTable;[old] = [code];}else{[...] = translation for [old];k = first character of [...];Output [...]k to CharStream;add [...]k to the StringTable;[old] = [code];}[code] = Next Code in the CodeStream;}词典编码词典编码主要利用数据本身包含许多重复的字符串的特性.例如:吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮. 我们如果用一些简单的代号代替这些字符串,就可以实现压缩,实际上就是利用了信源符号之间的相关性.字符串与代号的对应表就是词典. 实用的词典编码算法的核心就是如何动态地形成词典,以及如何选择输出格式以减小冗余. 第一类词典编码第一类词典法的想法是企图查找正在压缩的字符序列是否在以前输入的数据中出现过,然后用已经出现过的字符串替代重复的部分,它的输出仅仅是指向早期出现过的字符串的"指针". LZ77算法LZ77 算法在某种意义上又可以称为"滑动窗口压缩",该算法将一个虚拟的,可以跟随压缩进程滑动的窗口作为词典,要压缩的字符串如果在该窗口中出现,则输出其出现位置和长度.使用固定大小窗口进行词语匹配,而不是在所有已经编码的信息中匹配,是因为匹配算法的时间消耗往往很多,必须限制词典的大小才能保证算法的效率;随着压缩的进程滑动词典窗口,使其中总包含最近编码过的信息,是因为对大多数信息而言,要编码的字符串往往在最近的上下文中更容易找到匹配串. LZ77编码的基本流程1,从当前压缩位置开始,考察未编码的数据,并试图在滑动窗口中找出最长的匹配字符串,如果找到,则进行步骤2,否则进行步骤 3. 2,输出三元符号组( off, len, c ).其中off 为窗口中匹配字符串相对窗口边界的偏移,len 为可匹配的长度,c 为下一个字符,即不匹配的第一个字符.然后将窗口向后滑动len + 1 个字符,继续步骤1. 3,输出三元符号组( 0, 0, c ).其中c 为下一个字符.然后将窗口向后滑动 1 个字符,继续步骤1. LZ77算法LZ77编码举例 C A B A B B C B A A 5, 3, A ABC 7 5 2, 1, B B 5 4 0, 0, C -- 4 3 1, 1, B A 2 2 0, 0, A -- 1 1 输出匹配串位置步骤LZSS算法LZ77通过输出真实字符解决了在窗口中出现没有匹配串的问题,但这个解决方案包含有冗余信息.冗余信息表现在两个方面,一是空指针,二是编码器可能输出额外的字符,这种字符是指可能包含在下一个匹配串中的字符. LZSS算法的思想是如果匹配串的长度比指针本身的长度长就输出指针(匹配串长度大于等于MIN_LENGTH),否则就输出真实字符.另外要输出额外的标志位区分是指针还是字符. LZSS编码的基本流程1,从当前压缩位置开始,考察未编码的字符,并试图在滑动窗口中找出最长的匹配字符串,如果匹配串长度len大于等于最小匹配串长度(len >= MIN_LENGTH),则进行步骤2,否则进行步骤3. 2,输出指针二元组( off, len).其中off 为窗口中匹配字符串相对窗口边界的偏移,len 为匹配串的长度,然后将窗口向后滑动len 个字符,继续步骤 1. 3,输出当前字符c,然后将窗口向后滑动 1 个字符,继续步骤 1. LZSS编码举例 C B A A B B C B B A A字符11 10 9 8 7 6 5 4 3 2 1 位置C C 11 8 (7,3) AAB 8 7 (3,2) BB 6 6 C -- 5 5 B B 4 4 B -- 3 3 A A 2 2 A -- 1 1 输出匹配串位置步骤输入数据流: 编码过程MIN_LEN =2 LZSS算法在相同的计算机环境下,LZSS算法比LZ77可获得比较高的压缩比,而译码同样简单.这也就是为什么这种算法成为开发新算法的基础,许多后来开发的文档压缩程序都使用了LZSS的思想.例如,PKZip, GZip, ARJ, LHArc和ZOO等等,其差别仅仅是指针的长短和窗口的大小等有所不同. LZSS同样可以和熵编码联合使用,例如ARJ就与霍夫曼编码联用,而PKZip则与Shannon-Fano联用,它的后续版本也采用霍夫曼编码. 第二类词典编码第二类算法的想法是企图从输入的数据中创建一个"短语词典(dictionary of the phrases)",这种短语可以是任意字符的组合.编码数据过程中当遇到已经在词典中出现的"短语"时,编码器就输出这个词典中的短语的"索引号",而不是短语本身. LZ78算法LZ78的编码思想是不断地从字符流中提取新的字符串(String),通俗地理解为新"词条",然后用"代号"也就是码字(Code word)表示这个"词条".这样一来,对字符流的编码就变成了用码字(Code word)去替换字符流(Char stream),生成码字流(Code stream),从而达到压缩数据的目的. LZ78编码器的输出是码字-字符(W,C)对,每次输出一对到码字流中,与码字W相对应的字符串(String)用字符C进行扩展生成新的字符串(String),然后添加到词典中. LZ78编码算法步骤1:将词典和当前前缀P都初始化为空. 步骤2:当前字符C:=字符流中的下一个字符. 步骤3:判断P+C 是否在词典中(1)如果"是",则用C扩展P,即让P:=P+C,返回到步骤2. (2)如果"否",则输出与当前前缀P相对应的码字W和当前字符C, 即(W,C); 将P+C添加到词典中; 令P:=空值,并返回到步骤2 LZ78编码举例A B A C B C B B A字符9 8 7 6 5 4 3 2 1 位置(2, A) BA 8 5 (3, A) BCA 5 4 (2, C) BC 3 3 (0, B) B 2 2 (0, A) A 1 1 输出词典位置步骤输入数据流: 编码过程: LZW算法J.Ziv和A.Lempel在1978年首次发表了介绍第二类词典编码算法的文章.在他们的研究基础上,Terry A.Welch在1984年发表了改进这种编码算法的文章,因此把这种编码方法称为LZW(Lempel-Ziv Walch)压缩编码. 在编码原理上,LZW与LZ78相比有如下差别: LZW只输出代表词典中的字符串(String)的码字(code word).这就意味在开始时词典不能是空的,它必须包含可能在字符流出现中的所有单个字符.即在编码匹配时,至少可以在词典中找到长度为1的匹配串. LZW编码是围绕称为词典的转换表来完成的. LZW算法的词典LZW 编码器(软件编码器或硬件编码器)就是通过管理这个词典完成输入与输出之间的转换.LZW 编码器的输入是字符流(Char stream),字符流可以是用8位ASCII字符组成的字符串,而输出是用n位(例如12位)表示的码字流(Code stream),码字代表单个字符或多个字符组成的字符串(String). LZW编码算法步骤1:将词典初始化为包含所有可能的单字符,当前前缀P初始化为空. 步骤2:当前字符C:=字符流中的下一个字符. 步骤3:判断P+C是否在词典中(1)如果"是",则用C扩展P,即让P:=P+C,返回到步骤2. (2)如果"否",则输出与当前前缀P相对应的码字W; 将P+C添加到词典中; 令P:=C,并返回到步骤2 LZW编码举例C A B A B A B B A字符9 8 7 6 5 4 3 2 1 位置2 BB 5 2 2 2 BA 6 3 3 4 ABA 7 4 4 7 ABAC 8 6 5 4 3 2 1 码字1 AB 1 1C B A输出词典位置步骤输入数据流: 编码过程: LZW算法LZW算法得到普遍采用,它的速度比使用LZ77算法的速度快,因为它不需要执行那么多的缀-符串比较操作.对LZW算法进一步的改进是增加可变的码字长度,以及在词典中删除老的缀-符串.在GIF图像格式和UNIX的压缩程序中已经采用了这些改进措施之后的LZW算法. LZW算法取得了专利,专利权的所有者是美国的一个大型计算机公司—Unisys(优利系统公司),除了商业软件生产公司之外,可以免费使用LZW算法. 预测编码预测编码是数据压缩理论的一个重要分支.它根据离散信号之间存在一定相关性的特点,利用前面的一个或多个信号对下一个信号进行预测,然后对实际值和预测值的差(预测误差)进行编码.如果预测比较准确,那么误差信号就会很小,就可以用较少的码位进行编码,以达到数据压缩的目的. 第n个符号Xn的熵满足: 所以参与预测的符号越多,预测就越准确,该信源的不确定性就越小,数码率就可以降低.lzw压缩算法的c语言实现1 程序由五个模块组成。

相关文档
最新文档