背景:为了锻炼自己的代码能力,以及数据结构算法掌握的能力,做此项目来锻炼自己提高自己的能力,本项目运用了C++中的知识,比如模板类,仿函数等等,还用到了数据结构中的算法知识,比如建堆调堆、哈夫曼编码,还用到了文件操作的知识。总是试一次很好的训练。
下面列出代码:
建堆调堆头文件:Heap.h
#ifndef __HEAP_H__ #define __HEAP_H__ #include <iostream> #include <assert.h> #include <vector> #include "FileCompress.h" #include "HuffmanTree.h" template <typename T> struct Less { bool operator()(const T& left, const T& right)const { return left < right; } }; template<typename K> //模板的偏特化 struct Less<HuffmanNode<K>*> { bool operator()(const HuffmanNode<K>* left, const HuffmanNode<K>* right)const { return left->_weight < right->_weight; } }; //template <> //struct Less<CharInfo> //{ // bool operator()(const CharInfo& left, const CharInfo& right)const // { // return left < right; // } //}; template <typename T> struct Greater { bool operator()(const T& left, const T& right)const { return left > right; } }; template <typename T,template<class> class Compare = Greater> class Heap { friend std::ostream& operator<<<T,Compare>(std::ostream& out, const Heap<T,Compare>& heap); public: Heap(); Heap(const T* array, size_t size); Heap(const Heap<T,Compare>& heap); Heap<T,Compare>& operator=(const Heap<T, Compare>& heap); ~Heap(); void Push(const T& x); void Pop(); T Top()const; bool Empty()const; size_t Size()const; protected: void _AdjustDown(int parent); void _AdjustUp(int pos); protected: std::vector<T> _array; }; //堆排序 template <typename T, template<class> class Compare = Greater> void HeapSort(T* array, size_t size, const Compare<T>& com = Compare<T>()); //建初堆 template <typename T, template<class> class Compare = Greater> void CrtHeap(T* array, size_t size, const Compare<T>& com = Compare<T>()); //下调 template <typename T, template<class> class Compare = Greater> void AdjustDown(T* array, size_t size, int parent = 0, const Compare<T>& com = Compare<T>()); template <typename T, template<class> class Compare = Greater> std::ostream& operator<<(std::ostream& out, const Heap<T, Compare>& heap); template <typename T, template<class> class Compare = Greater> void GetTopK(T* array, const vector<T>& money, const size_t& k, const size_t& n, const Compare<T>& com = Compare<T>()); #endif /*__HEAP_H__*/
#define _CRT_SECURE_NO_WARNINGS 1 #include "Heap.h" template <typename T,template<class> class Compare> Heap<T,Compare>::Heap() {} template <typename T,template<class> class Compare> Heap<T,Compare>::~Heap() {} template <typename T,template<class> class Compare> Heap<T,Compare>::Heap(const T* array, size_t size) { this->_array.resize(size); for (size_t i = 0; i < size; ++i) { this->_array[i] = array[i]; } for (int i = (size - 2) / 2; i >= 0; --i) { this->_AdjustDown(i); } } template <typename T,template<class> class Compare> Heap<T,Compare>::Heap(const Heap<T,Compare>& heap) { size_t size = heap.size(); this->_array.resize(size); for (size_t i = 0; i < size; ++i) { this->_array[i] = heap._array[i]; } } template <typename T,template<class> class Compare> Heap<T,Compare>& Heap<T,Compare>::operator=(const Heap<T,Compare>& heap) { if (this != &heap) { this->_array = heap._array; } return *this; } template <typename T,template<class> class Compare> void Heap<T,Compare>::Push(const T& x) { size_t size = this->_array.size(); this->_array.push_back(x); this->_AdjustUp(size); } //Compare template <typename T,template<class> class Compare> void Heap<T,Compare>::_AdjustUp(int pos) { assert(pos<this->_array.size()); Compare<T> com; int parent = (pos - 1) / 2; int child = pos; while (parent >= 0 && com(this->_array[child], this->_array[parent])) { swap(this->_array[child], this->_array[parent]); child = parent; parent = (child - 1) / 2; } } template <typename T,template<class> class Compare> void Heap<T,Compare>::Pop() { assert(!this->_array.empty()); size_t size = this->_array.size(); swap(this->_array[0], this->_array[size - 1]); this->_array.pop_back(); this->_AdjustDown(0); } //Compare template <typename T,template<class> class Compare> void Heap<T,Compare>::_AdjustDown(int parent) { size_t child = parent * 2 + 1; size_t size = this->_array.size(); Compare<T> com; while (child < size) { if (child + 1 < size && com(this->_array[child + 1], this->_array[child])) { ++child; } if (com(this->_array[child], this->_array[parent])) { swap(this->_array[parent], this->_array[child]); parent = child; child = parent * 2 + 1; } else { break; } } } template <typename T,template<class> class Compare> T Heap<T,Compare>::Top()const { assert(!this->_array.empty()); return this->_array[0]; } template <typename T,template<class> class Compare> bool Heap<T,Compare>::Empty()const { return this->_array.empty(); } template <typename T,template<class> class Compare> size_t Heap<T,Compare>::Size()const { return this->_array.size(); } template <typename T,template<class> class Compare> std::ostream& operator<<(std::ostream& out, const Heap<T,Compare>& heap) { size_t size = heap._array.size(); for (size_t i = 0; i < size; ++i) { out << heap._array[i] << " "; } out << endl; return out; } //堆排序 //template <typename T> //void HeapSort(T* array, size_t size) //{ // //建初堆 // Heap<T,Compare> heap(array, size); // for (int i = size - 1; i >= 0; --i) // { // array[i] = heap.GetTop(); // heap.Pop(); // } //} template <typename T,template<class> class Compare> void HeapSort(T* array, size_t size, const Compare<T>& com) { CrtHeap(array, size, com);//建初堆 for (int i = size - 1; i > 0; --i) { swap(array[0], array[i]); //交换头和尾 AdjustDown(array, i, 0, com); //使得0...i-1也为堆 } } //建初堆 template <typename T, template<class> class Compare> void CrtHeap(T* array, size_t size, const Compare<T>& com) { int parent = (size - 2) / 2; for (int i = parent; i >= 0; --i) { AdjustDown(array, size, i, com); } } //下调 //Compare template <typename T,template<class> class Compare> void AdjustDown(T* array, size_t size, int parent, const Compare<T>& com) { int child = parent * 2 + 1; while (child < (int)size) { if (child + 1 < size && com(array[child + 1], array[child])) { ++child; } if (com(array[child], array[parent])) { swap(array[parent], array[child]); parent = child; child = parent * 2 + 1; } else { break; } } } template <typename T, template<class> class Compare> void GetTopK(T* array, const vector<T>& money, const size_t& k, const size_t& n, const Compare<T>& com) { assert(array); assert(k < n); for (size_t i = 0; i < k; ++i) { array[i] = money[i]; } //建堆 for (int i = (k - 2) / 2; i >= 0; --i) { AdjustDown(array, k, i, com); } for (int i = k; i < n; ++i) { if (com(array[0],money[i])) { array[0] = money[i]; AdjustDown(array, k, 0, com); } } }
#pragma once #ifndef __HUFFMAN_TREE_H__ #define __HUFFMAN_TREE_H__ #include <iostream> template <typename T> struct HuffmanNode { T _weight; HuffmanNode* _left; HuffmanNode* _right; HuffmanNode(T weight = 0) :_weight(weight), _left(NULL), _right(NULL) {} //建堆时要用 //bool operator<(const HuffmanNode* right) //{ // return this->_weight < right->_weight; //} }; template <typename T> class HuffmanTree { typedef HuffmanNode<T> Node; public: HuffmanTree(); HuffmanTree(const T* array, size_t size, int vailed = 0); Node* GetHuffmanNode(); ~HuffmanTree(); protected: static Node* _CreateHuffmanTree(const T* array, size_t size, int vailed = 0); static void _Clear(Node* root); protected: Node* _root; }; #endif /*__HUFFMAN_TREE_H__*/
建立哈夫曼数实现文件:HuffmanTree.hpp
#pragma once #ifndef __HUFFMAN_TREE_HPP__ #define __HUFFMAN_TREE_HPP__ #include "Heap.hpp" #include "HuffmanTree.h" template <typename T> HuffmanTree<T>::HuffmanTree() :_root(NULL) {} template <typename T> HuffmanTree<T>::HuffmanTree(const T* array, size_t size, int vailed) : _root(NULL) { this->_root = _CreateHuffmanTree(array, size, vailed); } template <typename T> HuffmanNode<T>* HuffmanTree<T>::_CreateHuffmanTree(const T* array, size_t size, int valid) { //选最小,减小堆 Heap<Node*, Less> heap; Node* parent = NULL; for (size_t i = 0; i < size; ++i)//往堆里入结点 { if (array[i] != valid) { heap.Push(new Node(array[i])); } } while (heap.Size() > 1) { Node* minFirst = heap.Top(); heap.Pop(); Node* minSecond = heap.Top(); heap.Pop(); parent = new Node(minFirst->_weight + minSecond->_weight); parent->_left = minFirst; parent->_right = minSecond; heap.Push(parent); } return parent; } template <typename T> HuffmanTree<T>::~HuffmanTree() { this->_Clear(this->_root); } template <typename T> void HuffmanTree<T>::_Clear(Node* root) { if (root) { _Clear(root->_left); _Clear(root->_right); delete root; } } template <typename T> HuffmanNode<T>* HuffmanTree<T>::GetHuffmanNode() { return this->_root; } #endif /*__HUFFMAN_TREE_HPP__*/
文件压缩头文件:FileCompress.h
#pragma once #ifndef __HUFFMAN_CODE_H__ #define __HUFFMAN_CODE_H__ #include <iostream> #include <vector> #include <string> #include "HuffmanTree.h" using namespace std; typedef unsigned long long TypeLong; struct CharInfo { unsigned char _ch; //字符 TypeLong _count;//出现次数 string _code;//Huffman编码 CharInfo(TypeLong count = 0) :_ch(0), _count(count) {} bool operator!=(const CharInfo& info)const { return this->_count != info._count; } bool operator<(const CharInfo& info)const { return this->_count < info._count; } CharInfo operator+(const CharInfo& info)const { return CharInfo(this->_count + info._count); } }; class FileCompress { public: FileCompress(); void CompressHuffCode(const char* filename); void UnCompressHuffCode(const char* filename); void PrintCode()const; protected: static void GenerateHuffmanCode(HuffmanNode<CharInfo>* root, FileCompress& file, string& code); protected: CharInfo _info[256]; }; #endif /*__HUFFMAN_CODE_H__*/
文件压缩实现文件:FileCompreess.cpp
#define _CRT_SECURE_NO_WARNINGS 1 #include <assert.h> #include "FileCompress.h" #include <io.h> #include <direct.h> #define __DEBUG_COUT__ FileCompress::FileCompress() { size_t size = sizeof(this->_info) / sizeof(this->_info[0]); for (size_t i = 0; i < size; ++i) { this->_info[i]._ch = i; this->_info[i]._count = 0; } } void FileCompress::CompressHuffCode(const char* filename) { assert(filename); FILE* fOut = fopen(filename, "rb"); assert(fOut); //统计字符出现的次数 char ch = fgetc(fOut); while (!feof(fOut)) { ++this->_info[(unsigned char)ch]._count; ch = fgetc(fOut); } //建立哈夫曼树 HuffmanTree<CharInfo> huffTree(this->_info, sizeof(this->_info) / sizeof(this->_info[0]), 0); //生成哈夫曼编码 string code; HuffmanNode<CharInfo>* root = huffTree.GetHuffmanNode(); GenerateHuffmanCode(root, *this, code); //生成压缩文件名及配置配置文件名 string fileNewName = (string)filename; size_t last_ = fileNewName.find_last_of('.'); size_t name_ = fileNewName.find_last_of('\\');//文件名 if (last_ < fileNewName.size()) { fileNewName.erase(last_); } char file[10]; strcpy(file, filename + name_+1); fileNewName += "yasuo\\"; char *fileName = (char *)fileNewName.c_str(), *tag, path[1000]; strcpy(path, fileName); int a = 0; for (tag = fileName; *tag; tag++) { if (*tag == '\\') { a = strlen(fileName) - strlen(tag); } } path[a] = NULL; char filePath[1000]; sprintf(filePath, "md %s", path); system(filePath); fileNewName += file; string fileInName = fileNewName;//压缩文件名 string fileConfig = fileInName;//配置文件名 last_ = fileNewName.find_last_of('.'); if (last_ < fileNewName.size()) { fileInName.erase(last_); fileConfig.erase(last_); } fileInName += ".huff"; fileConfig += ".config"; string tmp; //生成压缩配置文件 FILE* fConfig = fopen(fileConfig.c_str(), "wb"); char buff[20] = { 0 }; for (size_t i = 0; i < sizeof(this->_info) / sizeof(this->_info[0]); ++i) { if (this->_info[i]._count != 0) { tmp += this->_info[i]._ch; tmp += ':'; tmp += (string)_itoa((this->_info[i]._count), buff, 10); tmp += '\n'; fputs(tmp.c_str(), fConfig); tmp.clear(); } } //对文件进行压缩 FILE* fIn = fopen(fileInName.c_str(), "wb"); assert(fIn); fseek(fOut, 0, SEEK_SET); int pos = 0; unsigned char putch = 0; ch = fgetc(fOut); while (!feof(fOut)) { tmp = this->_info[(unsigned char)ch]._code; for (size_t i = 0; i < tmp.size(); ++i) { putch <<= 1; putch |= (tmp[i] - '0'); if (++pos == 8) { fputc(putch, fIn); pos = 0; putch = 0; } } ch = fgetc(fOut); } if (pos > 0) { putch <<= (8 - pos); fputc(putch, fIn); } fclose(fOut); fclose(fIn); fclose(fConfig); } void FileCompress::GenerateHuffmanCode(HuffmanNode<CharInfo>* root, FileCompress& file, string& code) { if (root == NULL) { return; } if (root->_left == NULL && root->_right == NULL) { file._info[root->_weight._ch]._code = code; return; } code.push_back('0'); GenerateHuffmanCode(root->_left, file, code); code.pop_back(); code.push_back('1'); GenerateHuffmanCode(root->_right, file, code); code.pop_back(); } void FileCompress::UnCompressHuffCode(const char* filename) { assert(filename); FILE* fOut = fopen(filename, "rb"); assert(fOut); //读取文件, string fileConfig = (string)filename; string fileNewName = (string)filename; string fileInName = fileConfig; size_t last_ = fileInName.find_last_of('.'); size_t name_ = fileNewName.find_last_of('\\'); if (name_ < fileNewName.size()) { fileConfig.erase(last_); fileNewName.erase(name_); } char file[10]; strcpy(file, fileConfig.c_str() + name_ + 1);//文件名 name_ = fileNewName.find_last_of('\\'); if (name_ < fileInName.size()) { fileInName.erase(name_+1); } fileInName += file; //弥补文件名 fileConfig += ".config"; fileInName += "_Com.txt"; FILE* fIn = fopen(fileInName.c_str(), "wb"); assert(fIn); FILE* fConfig = fopen(fileConfig.c_str(), "rb"); assert(fConfig); //修改_count,注意\n,有可能代表字符,有可能是行结束标志 char buff[20] = { 0 }; unsigned char ch = fgetc(fConfig); while (!feof(fConfig)) { fgetc(fConfig);//读取冒号 fgets(buff, 20, fConfig); this->_info[ch]._count = (TypeLong)atoi((buff)); ch = fgetc(fConfig); } //重建哈夫曼树 HuffmanTree<CharInfo> tree(this->_info, sizeof(this->_info) / sizeof(this->_info[0]), 0); HuffmanNode<CharInfo>* root = tree.GetHuffmanNode(); HuffmanNode<CharInfo>* cur = root; TypeLong countSum = root->_weight._count; //记录字符的总个数控制结束 ch = fgetc(fOut); int pos = 7; while (countSum > 0) { while (pos >= 0) { if ((ch & (1 << pos)) == 0) //向左走 { cur = cur->_left; } else { cur = cur->_right; } if (cur->_left == NULL && cur->_right == NULL) { fputc(cur->_weight._ch, fIn); #ifndef __DEBUG_COUT__ cout << cur->_weight._ch; #endif /*__DEBUG_COUT__*/ if (--countSum == 0)//将没有写的字符的次数减1 break; cur = root; } --pos; } pos = 7; ch = fgetc(fOut); } fclose(fIn); fclose(fOut); fclose(fConfig); } void FileCompress::PrintCode()const { for (int i = 0; i < 256; ++i) { if (this->_info[i]._count != 0) { cout << this->_info[i]._ch << ":>" << this->_info[i]._code << endl; } } }
#pragma once #ifndef __TIME_CHECK_H__ #define __TIME_CHECK_H__ #include <windows.h> class MyTimer { public: MyTimer() { QueryPerformanceFrequency(&_freq); costTime = 0.0; } void Start() { for (int i = 0; i<EN_NUMER; ++i) { QueryPerformanceCounter(&_array[i]._begin); } } void Stop() { for (int i = 0; i<EN_NUMER; ++i) { QueryPerformanceCounter(&_array[i]._end); } } void Reset() { costTime = 0.0; } void showTime() { double allTime = 0.0; for (int i = 0; i<EN_NUMER; ++i) { allTime += (((double)_array[i]._end.QuadPart - (double)_array[i]._begin.QuadPart) / (double)_freq.QuadPart); } costTime = allTime / EN_NUMER; costTime *= 1000000; if ((((int)costTime) / 1000000) > 0) { cout << costTime / 1000000 << " s" << endl; } else if (((int)costTime) / 1000 > 0) { cout << costTime / 1000 << " ms" << endl; } else { cout << costTime << " us" << endl; } } private: class Array { public: LARGE_INTEGER _begin; LARGE_INTEGER _end; }; enum{ EN_NUMER = 5 }; LARGE_INTEGER _freq; double costTime; Array _array[EN_NUMER]; }; #endif
测试代码:压缩测试函数,放在主函数里
void test() { string filename = "C:\\Users\\小明\\Desktop\\input.txt"; cout << "压缩时间"; MyTimer timer; timer.Start(); //////////////////////////////// FileCompress fc; fc.CompressHuffCode(filename.c_str()); ///////////////////////////////// timer.Stop(); timer.showTime(); }
void untest() { string filename = "C:\\Users\\小明\\Desktop\\inputyasuo\\input.huff"; cout << "解压时间"; MyTimer timer; timer.Start(); //////////////////////////////// FileCompress unfc; unfc.UnCompressHuffCode(filename.c_str()); ///////////////////////////////// timer.Stop(); timer.showTime(); }
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; #include "HuffmanTree.hpp" #include "FileCompress.h" #include "FileCompress.cpp" #include "TimeCheck.h" void test() { string filename = "C:\\Users\\小明\\Desktop\\input.txt"; //需要压缩的文件 cout << "压缩时间"; MyTimer timer; timer.Start(); //////////////////////////////// FileCompress fc; fc.CompressHuffCode(filename.c_str()); ///////////////////////////////// timer.Stop(); timer.showTime(); } void untest() { string filename = "C:\\Users\\小明\\Desktop\\inputyasuo\\input.huff"; //需要解压缩的文件名 cout << "解压时间"; MyTimer timer; timer.Start(); //////////////////////////////// FileCompress unfc; unfc.UnCompressHuffCode(filename.c_str()); ///////////////////////////////// timer.Stop(); timer.showTime(); } int main() { test(); untest(); system("pause"); return 0; }
现在测试的是我桌面上的一个文件:文件名为:input.txt
压缩过程
压缩和解压缩之后桌面显示:
解压缩文件:input_Com.txt
本项目特点:将压缩后的文件,以及配置文件新建立了一个文件夹,放在文件夹中,这样美观,易识别。
代码中还有很多不足,有些问题也未解决,欢迎各位批评指正!!! 我也会子啊后续努力中继续添加功能!