LZ77原理:

  • LZ77是基于字节的通用压缩算法,它的原理就是将源文件中的重复字节(即在前文中出现的重复字节)使用(offset,length,nextchar)的三元组进行替换。比如:mnoabczxyuvwabc123456abczxydefgh替换为:mnoabczxyuvm(9,3,1)23456(18,6,d)efgh
  • GZIP中进行了一个小小的改变,因为nextchar是否出现在三元组中,对压缩率的提升并不能起到什么作用,因此GZIP采用(距离,长度)对的方式进行替换,具体如下:
    mnoabczxyuvm(9,3)123456(18,6)defgh

LZ77压缩步骤

  1. LZ77压缩时,是在一个滑动窗口中进行的,初始状态下,先加载一个窗口的数据。随着压缩的进行,滑动窗口分为两部分,查找缓冲区和前向缓冲区。只有当匹配的字符串>=3个时才进行替换。
  2. 窗口的大小取为64K,分为两部分。因为窗口不能无限大,要考虑时间和空间成本。分为两部分方便了搬移和读取数据。
  3. 使用哈希表来实现高效的查找最长匹配串。
    ① 利用哈希函数计算该字符与紧跟其后的两个字符构成字符串的哈希地址
    ② 将该字符串中首字符在窗口中的索引插入上述计算出哈希位置的哈希桶中,返回插入之前该桶的状态
    ③ 根据2返回的状态监测是否找到匹配串。如果当前桶为空,说明未找到匹配,否则:可能找到匹配,再定位到匹配串位置详细进行匹配即可。
  4. 为了区分源字符与<距离,长度>对,在向压缩文件中写数据时可用0和1来进行区分,比如用0代表源字符,1代表<距离,长度>对。先将标记信息写入一个新的文件,最后两个文件合并成一个新的文件即可。

压缩文件格式

压缩格式分两个文件保存:

  1. 文件1保存原字符和距离长度对。
  2. 文件2保存比特位标记信息。

解压缩

  1. 从文件2中读取标记,并对该标记进行分析
  2. 如果当前标记是0,表示原字符,从文件1中读取一个字节,直接写到解压缩之后的文件中
  3. 如果当前标记是1,表示遇到(距离,长度对),从文件1中读取两个字节表示距离,再读取一个字节表示长度,从构建(距离,长度)对,然后从解压缩过的结果中找出匹配长度
  4. 获取下一个标记,直到所有的标记解析完。

Huffman原理:

  • 由给定的n个权值{ w1, w2, w3, … , wn}构造n棵只有根节点的二叉树森林F={T1, T2 , T3, … ,Tn},每棵二叉树Ti只有一个带权值wi的根节点,左右孩子均为空。
  • 重复以下步骤,直到F中只剩下一棵树为止
    • 在F中选取两棵根节点权值最小的二叉树,作为左右子树构造一棵新的二叉树,新二叉树根节点的权值为其左右子树根节点的权值之和
    • 在F中删除这两棵二叉树
    • 把新的二叉树加入到F中
  • 将Huffman树中左分支用0代替,右分支用1代替
  • 此时所有权值节点都在叶子位置,遍历每条到叶子节点的路径即可获取到字符的编码
  • Huffman编码不会出现一个编码是另一个编码前缀的这种情况,因为到达二叉树叶子节点的路径只有一条!!!

Huffman编码保证了二叉树的带权路径长度最小,提高了压缩率

Huffman压缩步骤

  1. 统计源文件中每个字符出现的次数:创建数组,以字符的ASCII码为索引值下标统计个数
  2. 以字符出现的次数为权值创建huffman树:使用优先队列(小根堆)创建Huffman树
  3. 通过huffman树获取每个字符对应的huffman编码 获取的编码可以放进一个字符串数组中,以字符的ASCII码为索引值下标
  4. 读取源文件,对源文件中的每个字符使用获取的huffman编码进行改写,将改写结果写到压缩文件中,直到文件结束。

Huffman压缩文件格式

压缩文件中除了要保存压缩数据,还必须保存解压缩需要用到的信息:

  1. 源文件的后缀
  2. 字符次数对的总行数
  3. 字符以及字符出现次数(为简单期间,每个字符放置一行)
  4. 压缩数据

Huffman解压缩

  • 从压缩文件中获取源文件的后缀
  • 从压缩文件中获取字符次数的总行数
  • 获取每个字符出现的次数
  • 重建huffman树
  • 解压缩:
    从压缩文件中一个一个字节的获取压缩数据(也可以自己创建一个缓冲区,一次读取较多字节的数据到缓冲区,然后一个一个字节从缓冲区里拿!),获取到一个字节的压缩数据,从根节点开始,按照该字节的二进制比特位信息遍历huffman树,该比特位是0,取当前节点的左孩子,否则取右孩子,直到遍历到叶子节点位置,该字符就被解析成功。此时返回根节点,继续此过程,直到所有的数据解析完毕。

遇见的错误

  • 哈希表初始化错误。
  • 按位与写成了逻辑与。
  • 在LZ77解压缩时,写入字符后都要刷新缓冲区,防止匹配字符串时失败。
  • 使用fopen函数对文件进行输出输入操作时,最好写成以二进制方式,否则可能会出现读取到特殊符号而终止,导致解压缩不完全(例如图片视频等,一个字节的数据可能出现全1,用文本读就会出现问题)
  • 以字符的ASCII码为下标进行统计时,注意使用unsigend char,因为字符的大小是-127到128,负数无法作为下标
  • 将一些特殊字符及其出现次数写入文件时,可能字符串构建时会出现错误(例如我使用sprintf在构建\0字符的出现次数时,字符串一直为空,原因是遇见\0 C风格字符串就结束了)

压缩率

文件类型 源文件大小 压缩大小 压缩率
视频/图片文件 10.3MB 10.3MB 100%
文本文件 12.0MB 8.51MB 70.9%

全部代码

详细代码请前往GitHub—>点我啊

FileCompressHuffman.hpp

#pragma once
#include<string>
#include<iostream>
#include"Huffman.hpp"class FileCompressHuffman {public:FileCompressHuffman();void CompressFile(const std::string& fileName);void UnCompressFile(const std::string& fileName);
private:void ReadHead(FILE* pRead, std::vector<int>& count);void WriteHead(FILE* pWrite, const std::vector<int>& count);void GetHuffmanCode(HuffManTreeNode* ptr, std::vector<std::string>& charPassWord);
};

HashTable.hpp

#pragma once
#include"Common.hpp"class HashTable {public:HashTable(USH size);~HashTable();void Insert(USH& matchhead, UCH ch, USH pos, USH& hashAddr);void hashFunc(USH& hashAddr, UCH ch);USH GetNext(USH matchHead);void Update();
private:USH H_SHIFT();
private:USH *prev_;USH *head_;
};

Huffman.hpp

#pragma once
#include<queue>
#include<vector>
#include<stack>struct HuffManTreeNode {HuffManTreeNode(unsigned long long weight, unsigned char ch = 0):pLeft_(nullptr), pRight_(nullptr), Weight_(weight), Ch_(ch){}HuffManTreeNode *pLeft_;HuffManTreeNode *pRight_;unsigned long long Weight_;                    //权值unsigned char Ch_;              //待压缩字符
};class Less {            //使用小堆
public:bool operator()(const HuffManTreeNode* pLeft, const HuffManTreeNode* pRight) {return pLeft->Weight_ > pRight->Weight_;}
};class HuffmanTree {typedef HuffManTreeNode Node;typedef HuffManTreeNode* PNode;
public:HuffmanTree(const std::vector<int> arr):pRoot_(nullptr){CreateHuffmanTree(arr);}~HuffmanTree() {std::stack<PNode> sa;PNode ptr = pRoot_;while (!sa.empty() || ptr) {while (ptr) {sa.push(ptr);ptr = ptr->pLeft_;}PNode del = sa.top();sa.pop();ptr = del->pRight_;delete del;}}PNode GetRoot() {return pRoot_;}
private:void CreateHuffmanTree(const std::vector<int> count) {//优先队列,小根堆std::priority_queue<PNode, std::vector<PNode>, Less> que;for (int i = 0; i < 256; ++i) {if (count[i] > 0) { //筛选出现过的字符,压入队列que.push(new Node(count[i], i));}}while (que.size() > 1) {PNode left = que.top();que.pop();PNode right = que.top();que.pop();PNode newNode = new Node(left->Weight_ + right->Weight_);newNode->pLeft_ = left;newNode->pRight_ = right;que.push(newNode);}pRoot_ = que.top();}
private:Node* pRoot_;
};

LZ77.hpp

#pragma once
#include<string>
#include"HashTable.hpp"class LZ77 {public:LZ77();~LZ77();void CompressionFile(const std::string& fileName);void UnCompressionFile(const std::string& fileName);
private:void MergeFile(FILE* fW, ULL fileSize);void fillWindow(USH& start, FILE* fR, size_t& readSize);USH  LongestMatch(USH matchHead, USH &curMatchDist, USH start);void WriteFlag(FILE* file, UCH& chNum, UCH& bitCount, bool isLen);
private:UCH* pWin_;HashTable ht_;std::string fileName_;
};

Common.hpp

#pragma oncetypedef unsigned char UCH;
typedef unsigned short USH;
typedef unsigned long long ULL;const USH MIN_MATCH = 3;     //最小匹配长度
const USH MAX_MATCH = 258;   //最大匹配长度
const USH WSIZE = 32 * 1024;   //32k

FileCompressHuffman.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"FileCompressHuffman.hpp"
#include<iostream>FileCompressHuffman::FileCompressHuffman(){}void FileCompressHuffman::CompressFile(const std::string& fileName) {FILE *pFile = fopen(fileName.c_str(), "rb");//因为这里压缩的不一定是文本文件//用二进制方式打开更为合理if (!pFile) {std::cout << "open file " << fileName << " error!" << std::endl;return;}//1、统计源文件中每个字符出现的次数unsigned char buf[1024] = { 0 };   //一次读取文件的1024个字节//这里不能出现负数,因为无法作为count数组的下标,所以要用unsigned char int rdSize = 0;std::vector<int> count;count.resize(256);while (1) {rdSize = fread(buf, 1, 1024, pFile);for (int i = 0; i < rdSize; ++i) {++count[buf[i]];}if (rdSize < 1024)break;}//2、以字符出现的次数为权值创建huffman树HuffmanTree tree(count);//3、获取每个字符的编码std::vector<std::string> strCode;strCode.resize(256);GetHuffmanCode(tree.GetRoot(), strCode);//4、用获取到的编码重新改写源文件FILE *pWrite = fopen("Huffman.bin", "wb");if (!pWrite) {std::cout << "open Huffman.bin error!" << std::endl;return;}//写入头部信息WriteHead(pWrite, count);fseek(pFile, 0, SEEK_SET);unsigned char ch = 0;int bitCount = 0;while (1) {rdSize = fread(buf, 1, 1024, pFile);for (int i = 0; i < rdSize; ++i) {std::string passWord = strCode[buf[i]];//读取buf[i]对应的密码for (size_t j = 0; j < passWord.size(); ++j) {ch <<= 1;++bitCount;if (passWord[j] == '1') {ch |= 1;}if (bitCount == 8) {fputc(ch, pWrite);bitCount = 0;ch = 0;}}}if (rdSize < 1024)break;}if(bitCount > 0){ch = ch << (8 - bitCount);fputc(ch, pWrite);}fclose(pFile);fclose(pWrite);
}
void FileCompressHuffman::UnCompressFile(const std::string& fileName) {FILE *pRead = fopen(fileName.c_str(), "rb");if (!pRead) {std::cout << "open file " << fileName << " error!" << std::endl;return;}//读取头部信息std::vector<int> count;count.resize(256);ReadHead(pRead, count);//创建Haffman树HuffmanTree tree(count);FILE *pWrite = fopen("h2.bin", "wb");if (pWrite == NULL) {std::cout << "open h2.bin error!" << std::endl;return;}unsigned char ch = 0;HuffManTreeNode* ptr = tree.GetRoot();unsigned long long fileSize = ptr->Weight_;char readBuf[1024] = { 0 };while (1) {int n = fread(readBuf, 1, 1024, pRead);if (!n)break;for (int i = 0; i < n; ++i) {ch = readBuf[i];for (int j = 0; j < 8; ++j) {if (ch & 0x80) {//最高位为1ptr = ptr->pRight_;}else {ptr = ptr->pLeft_;}ch = ch << 1;if (!ptr->pLeft_ && !ptr->pRight_) {//已经找到叶子节点fputc(ptr->Ch_, pWrite);--fileSize;ptr = tree.GetRoot();if (!fileSize)goto LOOP;}}}}
LOOP:fclose(pRead);fclose(pWrite);
}void FileCompressHuffman::ReadHead(FILE* pRead, std::vector<int>& count){char buf[1024] = { 0 };//读取行数信息fgets(buf, 1024, pRead);int rows = atoi(buf);for (int i = 0; i < rows; ++i) {fgets(buf, 1024, pRead);if (buf[0] == '\n') {fgets(buf + 1, 1023, pRead);}unsigned char ch = buf[0];int ret = atoi(buf + 2);count[ch] = ret;}
}
void FileCompressHuffman::WriteHead(FILE* pWrite, const std::vector<int>& count) {std::string headstr = "";int rows = 0;char str[1024] = { 0 };for (int i = 0; i < 256; ++i) {if (count[i] > 0) {unsigned char ch = i;int ret = count[i];//sprintf(str, "%c:%d\n", ch, ret);//headstr += str;headstr += ch;headstr += ':';_itoa(ret, str, 10);headstr += str;headstr += '\n';++rows;}}sprintf(str, "%d\n", rows);headstr = str + headstr;fwrite(headstr.c_str(), 1, headstr.size(), pWrite);
}
void FileCompressHuffman::GetHuffmanCode(HuffManTreeNode* ptr, std::vector<std::string>& charPassWord) {static std::string passWord = "";if (!ptr->pLeft_ && !ptr->pRight_) {//当它为叶子节点时charPassWord[ptr->Ch_] = passWord;return;}if (ptr->pLeft_) {passWord += '0';GetHuffmanCode(ptr->pLeft_, charPassWord);passWord.erase(passWord.end() - 1);}if (ptr->pRight_) {passWord += '1';GetHuffmanCode(ptr->pRight_, charPassWord);passWord.erase(passWord.end() - 1);}
}

HashTable.cpp

#include<string.h>
#include"HashTable.hpp"const USH HASH_BITS = 15;                  //哈希地址15位
const USH HASH_SIZE = (1 << HASH_BITS);    //哈希地址个数 32K
const USH HASH_MASK = HASH_SIZE - 1;       //防止溢出  低15位全1HashTable::HashTable(USH size):prev_(new USH[2*size]),head_(prev_+size)
{memset(prev_, 0, 2 * size * sizeof(USH));
}
HashTable::~HashTable() {delete[] prev_;prev_ = nullptr;
}
void HashTable::Insert(USH& matchhead, UCH ch, USH pos, USH& hashAddr) {hashFunc(hashAddr, ch);//获取本次插入的哈希地址matchhead = head_[hashAddr];//获取上一次匹配的字符串头//将新的哈希地址插入链表prev_[pos&HASH_MASK] = head_[hashAddr];head_[hashAddr] = pos;
}
USH HashTable::GetNext(USH matchHead) {return prev_[matchHead&HASH_MASK];
}
void HashTable::Update() {for (size_t i = 0; i < WSIZE; ++i) {//更新headif (head_[i] > WSIZE)head_[i] -= WSIZE;elsehead_[i] = 0;//更新previf (prev_[i] > WSIZE)prev_[i] -= WSIZE;elseprev_[i] = 0;}
}
void HashTable::hashFunc(USH& hashAddr, UCH ch) {hashAddr = (((hashAddr) << H_SHIFT()) ^ (ch))&HASH_MASK;
}
USH HashTable::H_SHIFT() {return (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
}

LZ77.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include"LZ77.hpp"const USH MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; //要保证最后一次匹配,最大匹配长度258
const USH MAX_DIST = WSIZE - MIN_LOOKAHEAD;    //最长匹配距离LZ77::LZ77():pWin_(new UCH[WSIZE * 2]),ht_(WSIZE)
{}
LZ77::~LZ77() {delete[] pWin_;pWin_ = nullptr;
}
void LZ77::CompressionFile(const std::string& fileName) {fileName_ = fileName;FILE* fR = fopen(fileName.c_str(), "rb");if (!fR) {std::cout << "待压缩文件打开失败!" << std::endl;return;}//计算文件大小fseek(fR, 0, SEEK_END);ULL fileSize = ftell(fR);if (fileSize <= MIN_MATCH) {std::cout << "文件太小!不进行压缩!!" << std::endl;return;}//将文件指针置回起始位置fseek(fR, 0, SEEK_SET);//从压缩文件中读取一个缓冲区的数据到窗口中size_t lookAhead = fread(pWin_, sizeof(UCH), 2 * WSIZE, fR);//计算前两个字符的哈希地址USH hashAddr = 0;for (UCH i = 0; i < MIN_MATCH - 1; ++i) {ht_.hashFunc(hashAddr, pWin_[i]);}FILE* fW = fopen("LZ77.bin", "wb");//写压缩数据FILE* fWT = fopen("3.bin", "wb");//写数据的标记if (!fW || !fWT) {std::cout << "文件打开失败" << std::endl;return;}USH matchHead = 0;//匹配链的头USH curMatchLen = 0; //最长匹配链的长度USH curMatchDist = 0; //最长匹配链的距离USH start = 0;  //查找字符串在缓冲区的地址UCH chNum = 0;   //将要写入的标记UCH bitCount = 0; //记录 标记写了多少位while (lookAhead) {//1.将当前三个字符插入到哈希表中,并获取匹配链的头ht_.Insert(matchHead, pWin_[start + 2], start, hashAddr);curMatchLen = 0;curMatchDist = 0;//2.验证在查找缓冲区中是否找到匹配,如果有匹配,找最长匹配if (matchHead > 0) {//顺着匹配链找最长匹配,最终带出<长度,距离>对curMatchLen = LongestMatch(matchHead, curMatchDist, start);}//3.验证是否找到匹配if (curMatchLen < MIN_MATCH) {//找到//写原字符fputc(pWin_[start], fW);//写标记WriteFlag(fWT, chNum, bitCount, false);++start;--lookAhead;}else {           //未找到//写长度UCH chlen = curMatchLen - 3;fputc(chlen, fW);//写距离fwrite(&curMatchDist, sizeof(curMatchDist), 1, fW);//写标记WriteFlag(fWT, chNum, bitCount, true);lookAhead -= curMatchLen;//将已经匹配的字符串按照三个一组将其插入到哈希表中++start;   //第一个字符已经插入--curMatchLen;while (curMatchLen) {ht_.Insert(matchHead, pWin_[start + 2], start, hashAddr);++start;--curMatchLen;}}//检测先行缓冲区中剩余字符个数if (lookAhead <= MIN_LOOKAHEAD)fillWindow(start, fR, lookAhead);}//将标记位数不够八位的写入if (bitCount > 0 && bitCount < 8) {chNum <<= (8 - bitCount);fputc(chNum, fWT);}fclose(fWT);fclose(fR);//合并压缩数据文件和标记文件MergeFile(fW, fileSize);fclose(fW);//将用来保存标记信息的临时文件删除掉if (remove("3.bin") != 0) {std::cout << "3.bin删除失败" << std::endl;}
}
void LZ77::MergeFile(FILE* fW, ULL fileSize) {//将压缩数据文件和标记信息文件合并//读取标记信息文件中内容,然后将结果写入到压缩文件中FILE* fR = fopen("3.bin", "rb");UCH *buff = new UCH[1024];ULL rSize = 0;while (1) {size_t readSize = fread(buff, sizeof(UCH), 1024, fR);if (readSize == 0)break;rSize += readSize;fwrite(buff, sizeof(UCH), readSize, fW);}fwrite(&rSize, sizeof(rSize), 1, fW);fwrite(&fileSize, sizeof(fileSize), 1, fW);delete[] buff;fclose(fR);
}
void LZ77::fillWindow(USH& start, FILE* fR, size_t& readSize) {//start压缩已经进行到右窗,先行缓冲区剩余数据不够MIN_LOOKAHEADif (start >= WSIZE) {//1.将右窗中的数据搬移到左窗memcpy(pWin_, pWin_ + WSIZE, WSIZE);memset(pWin_ + WSIZE, 0, WSIZE);start -= WSIZE;//2.更新哈希表ht_.Update();//3.向右窗中补充WSIZE个的待压缩数据if (!feof(fR))readSize += fread(pWin_ + WSIZE, sizeof(UCH), WSIZE, fR);}
}
USH LZ77::LongestMatch(USH matchHead, USH& MatchDist, USH start) {     //找最长匹配USH curMatchLen = 0;USH maxMatchLen = 0;USH maxMatchHead = 0;UCH matchCount = 255;//在先行缓冲区中查找匹配时,不能太远即不能超过MAX_DISTUSH limit = start > MAX_DIST ? start - MAX_DIST : 0;do {//最大匹配范围UCH* pStart = pWin_ + start;UCH* pEnd = pStart + MAX_MATCH;//查找缓冲区匹配串的起始UCH* ptr = pWin_ + matchHead;curMatchLen = 0;while (pStart < pEnd&&*pStart == *ptr) {++curMatchLen;++pStart;++ptr;}if (maxMatchLen < curMatchLen) {maxMatchLen = curMatchLen;maxMatchHead = matchHead;}} while ((matchHead = ht_.GetNext(matchHead)) > limit&&matchCount--);//获取最大匹配距离MatchDist = start - maxMatchHead;//获取最大匹配长度return maxMatchLen;
}
void LZ77::WriteFlag(FILE* file, UCH& chNum, UCH& bitCount, bool isLen) {chNum <<= 1;if (isLen) chNum |= 1;++bitCount;if (bitCount == 8) {fputc(chNum, file);bitCount = 0;chNum = 0;}
}
void LZ77::UnCompressionFile(const std::string& fileName) {FILE* fR = fopen(fileName.c_str(), "rb");    //读取压缩数据FILE* fRT = fopen(fileName.c_str(), "rb");   //读取标记if (!fR||!fRT) {std::cout << "压缩文件打开失败!" << std::endl;return;}ULL fileSize = 0;   //读取压缩数据大小fseek(fRT, 0 - sizeof(fileSize), SEEK_END);fread(&fileSize, sizeof(fileSize), 1, fRT);ULL flagSize = 0;  //读取标记文件大小fseek(fRT, 0 - sizeof(fileSize) - sizeof(flagSize), SEEK_END);fread(&flagSize, sizeof(flagSize), 1, fRT);//将文件指针指向标记文件起始fseek(fRT, 0 - sizeof(fileSize) - sizeof(flagSize) - flagSize, SEEK_END);std::string newFile = "new" + fileName_;FILE* fW = fopen(newFile.c_str(), "wb");  //将解压后的数据写入到新文件FILE* fWr = fopen(newFile.c_str(), "rb"); //读取新文件已写入的部分if (!fW||!fWr) {std::cout << "新文件打开/读取失败" << std::endl;return;}UCH chNum = 0;UCH bitCount = 0;ULL enCodeCount = 0;while (enCodeCount < fileSize) {//读取标记信息if (bitCount == 0) {  chNum = fgetc(fRT);bitCount = 8;}if (chNum & 0x80) {//是长度数据//读取长度USH strLength = fgetc(fR) + 3;//读取距离USH strDist = 0;fread(&strDist, sizeof(strDist), 1, fR);//清空缓冲区fflush(fW);enCodeCount += strLength;fseek(fWr, 0 - strDist, SEEK_END);UCH ch = 0;while (strLength) {  //fR:读取前文匹配串中的内容ch = fgetc(fWr);fputc(ch, fW);//在还原长度距离对时,一定要清空缓冲区,否则可能会还原出错fflush(fW);--strLength;}}else {//原始字符UCH ch = fgetc(fR);fputc(ch, fW);fflush(fW);++enCodeCount;}chNum <<= 1;--bitCount;}fclose(fR);fclose(fRT);fclose(fW);fclose(fWr);if (remove(fileName.c_str()) != 0) {std::cout << fileName << "删除失败" << std::endl;}
}

main.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"FileCompressHuffman.hpp"
#include"FileCompressHuffman.cpp"
#include"LZ77.hpp"void test() {LZ77 lz;FileCompressHuffman tree;lz.CompressionFile("IMG_5725.PNG");tree.CompressFile("LZ77.bin");   //指定要压缩的文件             tree.UnCompressFile("Huffman.bin");    //指定要解压的文件lz.UnCompressionFile("h2.bin");
}
int main() {test();_CrtDumpMemoryLeaks();system("pause");return 0;
}

基于LZ77算法和Huffman编码的文件压缩项目相关推荐

  1. huffman编码压缩c语言,用Huffman编码对文件进行压缩的C语言实现

    本文介绍了采用Huffman编码对ASCII码文件进行压缩的基本原理,并用C语言程序实现了这个压缩过程.文中给出了比较完整的C语言程序代码,可以直接用于调试实验. 福 建电 脑 21 0 2年第 1期 ...

  2. 基于Huffman树的文件压缩(详细)

    文件压缩 开发平台:Visual Studio 2008 开发技术:哈夫曼树,堆排序 项目流程: (1)统计要压缩的文件中各字符出现的次数,利用数据结构中的小堆来构建Huffman树,每次在堆顶选出两 ...

  3. smoteenn算法_基于EasyEnsemble算法和SMOTE算法的不均衡数据分类方法与流程

    本发明涉及不均衡数据二分类技术领域,尤其涉及一种基于EasyEnsemble算法和SMOTE算法的不均衡数据二分类方法. 背景技术: 数据不均衡指的是在一个样本数据集中,某一类的样本数远少于其他类的样 ...

  4. 哈夫曼编码与文件压缩

    一:哈夫曼树与哈夫曼编码 大家知道,文件压缩的原理么? 假如我们有一个文件,文件当中仅有 A.B.C.D.E 五种字符,这五种字符出现的频率分别为 5次.4次.3次.2次.1次. 我们知道每个英文字母 ...

  5. 使用哈夫曼编码实现文件压缩__win10,c++

    系统:win10 工具:vc6.0 //我加了个计时,用int存储字符总数 //因此增加一个限制:文件不可大于2GB #include<iostream> #include<time ...

  6. 哈夫曼字符串编码c语言实现,基于哈夫曼(haffuman)算法的文件压缩的实现(C语言)(原创)...

    本文首先简要阐述哈夫曼算法的基本思想,然后介绍了使用哈夫曼算法进行文件压缩和解压缩的 处理步骤,最后给出了C语言实现的文件压缩和解压缩的源代码. 哈夫曼算法的主要思想是: ①首先遍历要处理的字符串,得 ...

  7. 基于Huffman算法实现文件压缩解压缩(C语言)

    一.实现步骤 统计源文件中字符种类和频率 建立Huffman编码树 生成Huffman编码表 压缩文件时,字符匹配编码,将编码写入压缩后文件 解压缩文件时,读取编码,匹配编码表中的字符,写入解压缩后的 ...

  8. 【小项目】用Huffman树实现文件压缩并解压

    一.前言 如果你学习数据结构,就一定会学到Huffman树,而Huffman编码实际上上就是zip压缩的核心部分,所以,如果已经学习了Huffman树,为何不尝试写一个压缩程序出来呢? 如果你没有学习 ...

  9. Haskll Lesson:Huffman编码实现文本压缩

    微信公众号:牛顿一号 欢迎关注我,一起学习,一起进步! 一.Huffman编码理论 学习资料 https://web.stanford.edu/class/archive/cs/cs106b/cs10 ...

  10. 【数据结构】文件压缩项目

    项目名称:文件压缩 开发环境:vs2010 运用到的数据结构: 1.heap堆 2.huffmantree哈夫曼树 3.Huffmancode哈夫曼编码 4.面向对象C++编程语言 思路: 1.利用小 ...

最新文章

  1. GDC-Client使用
  2. 15-07-08 数组-- 手机号抽奖、福利彩票随机生成
  3. vue解决启动报错cjs loader.js Error: Cannot find module ‘../config‘问题
  4. 练习:自己写一个容器ArrayList集合 一一数组综合练习2
  5. opencv 安装_如何在 CentOS 8 上安装 OpenCV
  6. 【技术短文】基于深度负相关学习的人群计数方法
  7. Transformer 在美团搜索排序中的实践
  8. 【论文解读】NN如何在表格数据中战胜GBDT类模型!
  9. 推荐:解析“extern”
  10. 【欧洲已死】李开复:欧洲人工智能毫无希望
  11. Android精讲--界面编程2(布局管理器)
  12. 不需要PM3/PN532也可以搞定加密卡!利用小米9、小米手环NFC模拟加密门禁卡的傻瓜式保姆级教程
  13. Win10桌面图标箭头去掉的方法总结
  14. PhpSpreadsheet VS Box\Spout读取excel性能对比
  15. Matlab 许可证文件过期
  16. 大数据项目实战之阿里云服务器
  17. 点击进入我的QQ空间
  18. 日计划安排 --- 凡事预则立,不预则废
  19. 惠普暗影精灵u盘启动linux,暗影精灵5 安装w10+ Ubuntu18.0.4
  20. SQLServer 查询表的列名称、说明、备注、类型等

热门文章

  1. mysql课程设计论文_课程设计项目源码,课程设计毕业设计项目,计算机毕业设计网 - 代码货栈...
  2. 《小岛经济学》读书笔记摘录
  3. 双眼融合训练一个月_视觉融合功能的四种训练方法
  4. 文本表示与文本特征提取的区别
  5. 将多个excel合并成一个包含多个sheet的excel
  6. eclipse中debug断点上有一个斜杠是什么
  7. 应广单片机及mini-c快速入门
  8. C++实现走迷宫算法
  9. 走迷宫算法1(递归 非最短路径)
  10. Excel数据分析day1