哈夫曼编码压缩和解压缩文件——C++实现


实现效果

压缩前
在这里插入图片描述
压缩后
在这里插入图片描述

经验证解压缩前解压缩后文本一致,无出入


文件目录

binaryTreeNode.h
linkedBinaryTree.h
源.cpp

代码如下

binaryTreeNode.h

#ifndef binaryTreeNode_
#define binaryTreeNode_
#include<vector>
#include<bitset>
#include<cmath>
using namespace std;

template <class T>
struct binaryTreeNode
{
	int *character;
	string element;
	binaryTreeNode<T> *leftChild,   // left subtree
		*rightChild;  // right subtree
	binaryTreeNode() {
		element = "";
		character = nullptr;
		leftChild = rightChild = NULL;
	}
	binaryTreeNode(
		binaryTreeNode *theLeftChild,
		binaryTreeNode *theRightChild)
	{
		element = "";
		character = nullptr;
		leftChild = theLeftChild;
		rightChild = theRightChild;
	}
	binaryTreeNode(int c) {
		element = "";
		character = new int(c);
		leftChild = rightChild = NULL;
	}
};

#endif
#pragma once


linkedBinaryTree.h

#include<bitset>
#include <iostream>
#include<sstream>
#include <stdio.h>
#include<map>
#include<iterator>
#include<fstream>
#include<iomanip>
#include<list>
#include "binaryTreeNode.h"
using namespace std;
template <class E>
class linkedBinaryTree {
public:
	binaryTreeNode<E> *root;
	int treeSize;
	linkedBinaryTree() { root = nullptr; treeSize = 0; }
	bool empty() {
		if (this->treeSize == 0)return 1;
		return 0;
	}
	map<char, string> huffmanMap;
	void makeTree(
		linkedBinaryTree<E>&, linkedBinaryTree<E>&);
	void makeTree(int i);

	void visit2(binaryTreeNode<E>*t);
	int count;
	void preOrder(binaryTreeNode<E> *t);

	void toMap(binaryTreeNode<E>*t);
	static void output(binaryTreeNode<E> *t)
	{
		cout << t->element << ' ';
	}
	void printMap();
	void zip(string a, string b);
};

template<class T>
class huffmanNode {
public:
	linkedBinaryTree<int> *tree;
	T weight;
	operator T () const { return weight; }
	huffmanNode() {
		weight = 0;
		tree = new linkedBinaryTree<T>;
	}
};

template<class E>
void visit(binaryTreeNode<E>*t) {
	cout << t->element;
	cout << endl;
}

template<class T>
class minHeap
{
public:
	minHeap(int initialCapacity = 10);
	~minHeap() { delete[] heap; }
	bool empty() const { return heapSize == 0; }
	int size() const
	{
		return heapSize;
	}
	const T& top()
	{// return min element
		if (heapSize == 0)
		{
			cout << "empty" << endl;

		}
		return heap[1];
	}
	void pop();
	void push(const T&);
	void initialize(T *, int);
	void deactivateArray()
	{
		heap = NULL; arrayLength = heapSize = 0;
	}
	void output(ostream& out) const;
private:
	int heapSize;       // number of elements in queue
	int arrayLength;    // queue capacity + 1
	T *heap;            // element array
};

template<class T>
minHeap<T>::minHeap(int initialCapacity)
{// Constructor.
	if (initialCapacity < 1)
	{
		ostringstream s;
		s << "Initial capacity = " << initialCapacity << " Must be > 0";
	}
	arrayLength = initialCapacity + 1;
	heap = new T[arrayLength];
	heapSize = 0;
}

template<class T>
void minHeap<T>::push(const T& theElement)
{// Add theElement to heap.

   // increase array length if necessary
	if (heapSize == arrayLength - 1)
	{// double array length
		cout << "full" << endl;
		return;
	}

	// find place for theElement
	// currentNode starts at new leaf and moves up tree
	int currentNode = ++heapSize;
	while (currentNode != 1 && heap[currentNode / 2] > theElement)
	{
		// cannot put theElement in heap[currentNode]
		heap[currentNode] = heap[currentNode / 2]; // move element down
		currentNode /= 2;                          // move to parent
	}

	heap[currentNode] = theElement;
}

template<class T>
void minHeap<T>::pop()
{// Remove max element.
   // if heap is empty return null
	if (heapSize == 0)   // heap empty
	{
		cout << "empty" << endl;
		return;
	}

	// Delete min element
	heap[1].~T();

	// Remove last element and reheapify
	T lastElement = heap[heapSize--];

	// find place for lastElement starting at root
	int currentNode = 1,
		child = 2;     // child of currentNode
	while (child <= heapSize)
	{
		// heap[child] should be smaller child of currentNode
		if (child < heapSize && heap[child] > heap[child + 1])
			child++;

		// can we put lastElement in heap[currentNode]?
		if (lastElement <= heap[child])
			break;   // yes

		 // no
		heap[currentNode] = heap[child]; // move child up
		currentNode = child;             // move down a level
		child *= 2;
	}
	heap[currentNode] = lastElement;
}

template<class T>
void minHeap<T>::initialize(T *theHeap, int theSize)
{// Initialize max heap to element array theHeap[1:theSize].
	delete[] heap;
	heap = theHeap;
	heapSize = theSize;

	// heapify
	for (int root = heapSize / 2; root >= 1; root--)
	{
		T rootElement = heap[root];

		// find place to put rootElement
		int child = 2 * root; // parent of child is target
							  // location for rootElement
		while (child <= heapSize)
		{
			// heap[child] should be smaller sibling
			if (child < heapSize && heap[child] > heap[child + 1])
				child++;

			// can we put rootElement in heap[child/2]?
			if (rootElement <= heap[child])
				break;  // yes

			 // no
			heap[child / 2] = heap[child]; // move child up
			child *= 2;                    // move down a level
		}
		heap[child / 2] = rootElement;
	}
}

template<class T>
void minHeap<T>::output(ostream& out) const
{// Put the array into the stream out.
	copy(heap + 1, heap + heapSize + 1, ostream_iterator<T>(cout, "  "));
}

// overload <<
template <class T>
ostream& operator<<(ostream& out, const minHeap<T>& x)
{
	x.output(out); return out;
}

//judge this node if leaf or not
template<class T>
bool f(binaryTreeNode<T>*n) {
	if (n->leftChild == nullptr&&n->rightChild == nullptr)
		return 1;
	return 0;
}
//	template<class E>
//	int linkedBinaryTree<E>::size() {
//		return this->treeSize;
//	}
//	template<class E>
//	E* linkedBinaryTree<E>::rootElement() const
//	{// Return NULL if no root. Otherwise, return pointer to root element.
//		if (treeSize == 0)
//			return nullptr;  // no root
//		else
//			return &root->element;
//	}
template<class E>
void linkedBinaryTree<E>::makeTree(int i) {
	root = new binaryTreeNode<E>(i);
	treeSize++;
	return;
}
template<class E>
void linkedBinaryTree<E>::makeTree(linkedBinaryTree<E>& left, linkedBinaryTree<E>& right)
{// Combine left, right, and element to make new tree.
 // left, right, and this must be different trees.
   // create combined tree
	root = new binaryTreeNode<E>(left.root, right.root);
	treeSize = left.treeSize + right.treeSize + 1;
	// deny access from trees left and right
	left.root = right.root = nullptr;
	left.treeSize = right.treeSize = 0;
}

template<class E>
void linkedBinaryTree<E>::preOrder(binaryTreeNode<E> *t)
{// Preorder traversal.
	if (t != nullptr)
	{
		visit(t);
		preOrder(t->leftChild);
		preOrder(t->rightChild);
	}
}

template<class E>
void postOrder(binaryTreeNode<E> *t)
{// Postorder traversal.
	if (t != nullptr)
	{
		postOrder(t->leftChild);
		postOrder(t->rightChild);
		visit(t);
	}
}
template<class E>
void linkedBinaryTree<E>::toMap(binaryTreeNode<E>*t) {
	if (t != nullptr)
	{
		toMap(t->leftChild);
		toMap(t->rightChild);
		visit2(t);
	}
}

template<class T>
void show(binaryTreeNode<T> *x, int d) {
	if (x != NULL) {
		show(x->rightChild, d + 1);
		cout << setw(5 * d) << " " << x->element << endl;
		show(x->leftChild, d + 1);
	}
}

//translate charachter to 01 string
template<class T>
void element_tanslate(binaryTreeNode<T>*t, string a) {
	if (t->character != nullptr)
	{
		t->element = a;
		return;
	}
	if (t->leftChild)
	{
		a += '0';
		element_tanslate(t->leftChild, a);
	}
	a.pop_back();// most point!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	if (t->rightChild) {
		a += '1';
		element_tanslate(t->rightChild, a);
	}
	a.pop_back();
	return;
}

template<class E>
void linkedBinaryTree<E>::visit2(binaryTreeNode<E>*t) {
	if (t->character != nullptr) {
		char a = (char)(*t->character);
		huffmanMap.insert(map<char, string>::value_type(a, t->element));
	}
}

//print map on screen
template<class E>
void linkedBinaryTree<E>::printMap() {
	map<char, string>::iterator it;
	for (it = huffmanMap.begin(); it != huffmanMap.end(); ++it)
	{
		cout << it->first;
		cout << it->second;
		cout << endl;
	}
}
//print map in file


//zip
template<class E>
void linkedBinaryTree<E>::zip(string zip_before, string zip_after) {
	ifstream f_zip_before(zip_before, ios::in);
	ofstream f_zip_after(zip_after, ios::out | ios::binary | ios::app);
	string sum = "";
	while (f_zip_before.peek() != EOF)
	{
		char m1;
		f_zip_before.get(m1);
		string s = huffmanMap[m1];
		//this is the point
		sum += s;
	}

	//print zip after
	cout << "----------------------zip after-----------------------" << endl;
	cout << sum << endl << endl;

	int a = floor(sum.length() / 8), b = sum.length() % 8;
	f_zip_after.write((char*)&a, sizeof(int));
	f_zip_after.write((char*)&b, sizeof(int));
	for (int i = 0; i < sum.length(); i += 8) {
		bitset<8> a(sum, i, i + 8);
		f_zip_after.write((char*)&a, sizeof(bool));
		if ((i + 8) > sum.length())
		{
			bitset<8> a(sum, i, sum.length());
			f_zip_after.write((char*)&a, sizeof(bool));
			break;
		}
	}
	f_zip_after.close();
	f_zip_before.close();
}
//unzip
string Expend(string txt, binaryTreeNode<int>*t) {
	
	string re = "";

	for (int i = 0; i < txt.length(); i) {
		// most point!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		binaryTreeNode<int> *x = t;
		while (!f<int>(x)) {
			if (txt[i] == '0')
				x = x->leftChild;
			else if (txt[i] == '1')
				x = x->rightChild;
			i++;
		}
		re += (char)*x->character;
		x = t;
	}
	return re;
}
void unzip(string unzip_before, string unzip_after) {
	ifstream f_unzip_before(unzip_before, ios::in | ios::binary);
	ofstream f_unzip_after(unzip_after, ios::out);
	//read the charachters categroies
	int count;
	//read  characters

	f_unzip_before.read((char*)&count, sizeof(int));
	int *charachters = new int[count];
	int *weight = new int[count];
	for (int i = 0; i < count; i++) {
		f_unzip_before.read((char*)&charachters[i], sizeof(int));
	}
	for (int i = 0; i < count; i++)
		f_unzip_before.read((char*)&weight[i], sizeof(int));
	//creat huffmantree
	huffmanNode<int> *hNode = new huffmanNode<int>[count];
	minHeap<huffmanNode<int>> heap(count);
	for (int i = 0; i < count; i++)
	{
		hNode[i].weight = weight[i];
		hNode[i].tree = new linkedBinaryTree<int>;
		hNode[i].tree->makeTree(charachters[i]);
		heap.push(hNode[i]);
	}
	// repeatedly combine trees from min heap
	// until only one tree remains
	huffmanNode<int> w, x, y;
	linkedBinaryTree<int> *z;
	for (int i = 1; i < count; i++)
	{
		// remove two lightest trees from the min heap
		x = heap.top(); heap.pop();
		y = heap.top(); heap.pop();

		// combine into a single tree
		z = new linkedBinaryTree<int>;
		z->makeTree(*x.tree, *y.tree);
		w.weight = x.weight + y.weight;
		w.tree = z;
		heap.push(w);
		delete x.tree;
		delete y.tree;
	}
	//read the zip code
	string sum = "";
	int times, b;
	f_unzip_before.read((char*)&times, sizeof(int));
	f_unzip_before.read((char*)&b, sizeof(int));
	for (int i = 0; i < times; i++) {
		bitset<8> d;
		f_unzip_before.read((char*)&d, sizeof(bool));
		sum += d.to_string();
	}
	bitset<8> d;
	f_unzip_before.read((char*)&d, sizeof(bool));
	string k = d.to_string();
	for (int i = 8 - b; i < 8; i++)
		sum += k[i];

	// test get zip_after code whether rigth or not
	cout << "----------------------------------get from zip file---------------------------" << endl;
	cout << sum << endl << endl;

	int q = 0;
	binaryTreeNode<int> *t = heap.top().tree->root;
	element_tanslate(t, "");
	cout << "解压时的树" << endl;
	show<int>(t, 5);
	cout << "end" << endl;
	string unzip = Expend(sum, t);
	f_unzip_after << unzip;

	f_unzip_after.close();
	f_unzip_before.close();
}
#pragma once


源.cpp

#include<iostream>
#include<string>
#include<fstream>
#include"linkedBinaryTree.h"
#include<algorithm>
#include <cstdlib>    
#include<vector>
using namespace std;
int countCharacter[200];
int cmp(const pair<int, int>& x, const pair<int, int>& y)
{
	return x.second < y.second;
}
template <class T>
linkedBinaryTree<int>* huffmanTree(T weight[], int n, string s)
{// Generate Huffman tree with weights weight[1:n], n >= 1.
   // create an array of single node trees
	int count = 0;	map<int, int, greater<int> > show_map_ans;
	for (int i = 0; i < n; i++)
		if (weight[i])count++;
	huffmanNode<T> *hNode = new huffmanNode<T>[count + 1];
	int q = 1;

	for (int i = 0; i < n; i++) {
		if (weight[i]) {
			//print pre character times
			cout << (char)i << "   " << i << "  " << weight[i] << endl;
			show_map_ans.insert(map<int, int>::value_type(i, weight[i]));
			hNode[q].weight = weight[i];
			hNode[q].tree = new linkedBinaryTree<int>;
			hNode[q].tree->makeTree(i);
			q++;
		}
	}
	int *a = new int[count];
	int *b = new int[count];
	typedef pair<int, int> PAIR;
	vector<PAIR> show_map_ans_vec(show_map_ans.begin(), show_map_ans.end());//put map element into vector
	sort(show_map_ans_vec.begin(), show_map_ans_vec.end(), cmp);//use sort 
	for (int i = 0; i != show_map_ans_vec.size(); ++i) {//show element
		a[i] = (int)show_map_ans_vec[i].first;
		b[i] = (int)show_map_ans_vec[i].second;
		/*cout<<a[i]<< endl;*/
	}
	ofstream ofile2(s, ios::in | ios::binary);
	ofile2.write((char*)&count, sizeof(int));
	for (int it = 0; it < count; it++)
	{
		ofile2.write((char*)&a[it], sizeof(int));
	}
	for (int it = 0; it < count; it++)
		ofile2.write((char*)&b[it], sizeof(int));
	ofile2.close();
	// make node array into a min heap
	minHeap<huffmanNode<T> > heap(count);
	heap.initialize(hNode, count);
	//test minHeap 
	//for (int i = 0; i < count; i++)
	//{
	//	huffmanNode<T> m = heap.top();
	//	cout << *m.tree->root->character << endl;
	//	heap.pop();
	//}
	// repeatedly combine trees from min heap
	// until only one tree remains
	huffmanNode<T> w, x, y;
	linkedBinaryTree<int> *z;
	for (int i = 1; i < count; i++)
	{
		// remove two lightest trees from the min heap
		x = heap.top(); heap.pop();
		y = heap.top(); heap.pop();

		// combine into a single tree
		z = new linkedBinaryTree<int>;
		z->makeTree(*x.tree, *y.tree);
		w.weight = x.weight + y.weight;
		w.tree = z;
		heap.push(w);
		delete x.tree;
		delete y.tree;
	}
	// destructor for min heap deletes hNode
	return heap.top().tree;
}
int main(void)
{
	ifstream infile("zip_before.txt");
	//initialization countCharachter
	for (int i = 0; i < 200; i++)
		countCharacter[i] = 0;

	//pre charachter read file 
	char c;
	if (infile.peek() == EOF)
	{
		cout << "this file is empty!!!" << endl;
		exit(1);
	}
	while (infile.peek() != EOF)
	{
		infile.get(c);
		countCharacter[c]++;
	}
	infile.close();
	//build huffmanTree
	cout << "-------------------print charachters the file has and occure times--------------" << endl;
	linkedBinaryTree<int> *x = huffmanTree(countCharacter, 200, "zip_after.txt");
	//print 
	cout << endl << endl;
	cout << "-----------------print huffmanTree postOrder-----------------" << endl;
	/*vector<bitset<1>> a;*/
	/*.push_back(0);*/
	element_tanslate(x->root, "");
	cout << "打印压缩时的树" << endl;
	show<int>(x->root, 5);

	cout << "-------------print map------------" << endl;
	x->toMap(x->root);
	x->printMap();
	//x->printMap_tofile("zip_after_map.bat");

	x->zip("zip_before.txt", "zip_after.txt");
	//
	unzip("zip_after.txt", "unzip_after.txt");

	return 0;
}

发布了40 篇原创文章 · 获赞 57 · 访问量 2750

猜你喜欢

转载自blog.csdn.net/weixin_44984664/article/details/105131051