见识了360压缩的神奇后,想要实现自己的文件压缩程序,然后花了近一个星期的时间去完成文件压缩与解压缩,期间有很多坑,花了很长时间去调试它,最后把坑给填了(真心的感受到了程序员写代码时的小小粗心会把自己给坑惨)。以下是些程序时的一些坑:
- 在windows下回车的字符是‘\r’'\n',编译器在读取字符时读取到'\r'后再读取到'\n'就会转换为回车。。。
- 在解压缩小文件时不会出现的问题在解压缩大文件时会出现。最常见的时没有解压缩完文件就退出了,因为会出现一些控制字符导致程序提前退出。
- 压缩汉字的时候 要使用unsigned char!!!
正如标题所说,实现文件压缩我是使用哈夫曼树产生哈夫曼编码,使用哈夫曼编码来压缩文件。
构造哈夫曼树的key值是文件中每个字符出现的次数。将出现的字符插入一个最小堆中,每次从堆中取出出现次数最少的字符构造哈夫曼树。
为此,我们先实现一个最小堆:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<assert.h>
//#include"HaffmanTree.h"
using namespace std;
template<class T>
struct Less
{
bool operator()(const T& l, const T& r)
{
return l < r;
}
};
template<class T>
struct Greater
{
bool operator()(const T& l, const T& r)
{
return l > r;
}
};
template<class T>
struct Less<T*>
{
bool operator()(const T*Nodel, const T*Noder)
{
return Nodel->_wight < Noder->_wight;
}
};
template<class T,class Continer = Less<T>>//默认为小堆
class Heap
{
public:
Heap(){};
Heap(const T* a, size_t size,const T& invalid);
Heap(vector<T> a);
Heap(const vector<T>& v);
void Push(const T& x);
void Pop();
T& GetTop();
bool Empty();
size_t Size();
void HeapSort(T* a, size_t size);
protected:
void _AdjustDown(size_t parent);
void _AdjustUp(int child);
protected:
vector<T> _a;
};
template<class T, class Continer = Less<T>>
Heap<T, Continer>::Heap(const T* a, size_t size,const T& invalid)
{
_a.reserve(size);
for (size_t i = 0; i < size; ++i)
{
if (a[i] != invalid)
{
_a.push_back(a[i]);
}
}
//建堆
for (int i = (_a.size() - 2) / 2; i >= 0; i--)
//从第一个非叶子结点开始下调,叶子结点可以看作是一个大堆或小堆
{
_AdjustDown(i);
}
}
template<class T, class Continer = Less<T>>
Heap<T, Continer>::Heap(vector<T> a)
{
_a.swap(a);
// 建堆
for (int i = (_a.size() - 2) / 2; i >= 0; --i)
{
_AdjustDown(i);
}
}
template&