一个哈夫曼编码实例《压缩一段字符串》C++

哈夫曼编码的几个步骤:

1.统计词频

2.将词频数据放到优先队列(priority_queue)中,并标记这些是叶子节点

3.新建一个空节点,取出优先队列中词频最小的两个节点作为左右孩子,并把两个词频相加。最后把新的节点再重新加到队列中,直到队列中只有一个节点,此时哈夫曼树就建立好了。

4.遍历哈夫曼树得到映射表

5.根据字符串对应的哈夫曼编码进行压缩

先观察一下运行结果:

代码如下:

代码比较多,不过都是基本语法,相信你能看懂的!!!!(实在看不懂的,耐心点,可以评论留言)

#include <iostream>
#include <cstring>
#include <string>
#include <queue>

using namespace std;
struct word_count_node {
	char s;
	int weight;
	bool leaf;
	word_count_node *lch, *rch;
};
struct tmp2
{
	bool operator() (word_count_node *a, word_count_node *b)
	{
		return a->weight > b->weight;
	}
};

struct word_map {
	unsigned char code;
	int count;
	bool coded = false;
	int bit;
};

void printHfmCode(int c,int bit, int count) {
	if (bit == -1 || count == 0)return;
	int value = (int)(c&(1 << bit));
	cout << (int)(value > 0);
	printHfmCode(c, bit - 1,count-1);
}

void getMap(word_count_node *huffmanTree, word_map *w_map, unsigned char code, int bit) {
	if (huffmanTree) {
		if (huffmanTree->leaf == false) {
			getMap(huffmanTree->lch, w_map, code, bit + 1);
			getMap(huffmanTree->rch, w_map, (code | (128 >> bit)), bit + 1);
		}
		else {
			w_map[huffmanTree->s].code = code;
			w_map[huffmanTree->s].coded = true;
			w_map[huffmanTree->s].bit = bit;
			w_map[huffmanTree->s].count = huffmanTree->weight;
		}
	}
}

void printbin(char c, int k) {
	if (k == 8)return;
	cout << (c && (128 >> k));
}

void getDecode(char &ch, unsigned char *encodeStr, int &index, int &step, word_count_node *huffmanTree) {
	if (huffmanTree->leaf == true) {
		ch = huffmanTree->s;
		return;
	}
	else {
		unsigned char t = *(encodeStr + index);
		int i = t & (128 >> step);
		step++;
		if (step == 8) {
			step = 0; 
			index++;
		}
		if (i == 0)getDecode(ch, encodeStr, index, step, huffmanTree->lch);
		else if (i > 0)getDecode(ch, encodeStr, index, step, huffmanTree->rch);
	}
}



int main()
{
	string str = "There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do.";
	cout << "源字符串:" << endl;
	cout << str << endl << endl;
	//统计词频
	int count[128];
	for (int i = 0; i < 128; i++)count[i] = 0;
	for (int i = 0; i < str.length(); i++) {
		count[str[i]]++;
	}
	count[0] = 1;
	
	//统计结果放到优先队列里
	cout << "词频统计:" << endl;
	priority_queue<word_count_node*,vector<word_count_node*>, tmp2> wordCount;
	int showTimes = 0;
	for (int i = 0; i < 128; i++) {
		if (count[i] > 0) {
			showTimes++;
			word_count_node *w_count = (word_count_node*)malloc(sizeof(word_count_node));
			w_count->lch = NULL;
			w_count->rch = NULL;
			w_count->leaf = true;
			w_count->weight = count[i];//权重
			w_count->s = (char)i;
			wordCount.push(w_count);
			
			cout << (char)i << ":" << count[i] << "  ";
			if (showTimes > 16) {
				cout << endl;
				showTimes = 0;
			}
		}
	}
	cout << endl << endl;

	//根据优先队列建立哈夫曼树
	while (wordCount.size() > 1) {
		word_count_node *rch = wordCount.top();
		wordCount.pop();
		word_count_node *lch = wordCount.top();
		wordCount.pop();
		word_count_node *w_count = (word_count_node*)malloc(sizeof(word_count_node));
		w_count->lch = lch;
		w_count->rch = rch;
		w_count->s = 0;
		w_count->leaf = false;
		w_count->weight = lch->weight + rch->weight;
		wordCount.push(w_count);
	}
	word_count_node *huffmanTree = wordCount.top();//取出哈夫曼树
	wordCount.pop();

	//根据哈夫曼树生成映射表
	word_map w_map[128];//存储映射信息
	for (int i = 0; i < 128; i++) {
		w_map[i].coded = false;
	}
	getMap(huffmanTree, w_map,0,0);//遍历哈夫曼树得到所有字母映射信息

	//打印映射表
	cout << "哈夫曼编码:" << endl;
	showTimes = 0;
	for (int i = 0; i < 128; i++) {
		if (w_map[i].coded == true) {		
			cout << (char)i<<": ";
			printHfmCode(w_map[i].code,7,w_map[i].bit);
			cout << "\t  ";
			
			showTimes++;
			if (showTimes > 4) {
				showTimes = 0;
				cout << endl;
			}
		}
	}
	cout << endl << endl;

	//根据映射压缩字符串
	cout << "压缩后的结果:" << endl;

	计算存储压缩后的编码长度
	int bitCount = 0;
	for (int i = 0; i < 128; i++) {
		if (w_map[i].coded == true) {
			bitCount += w_map[i].bit*w_map[i].count;
		}
	}

	新建一个空字符串
	unsigned char *encodeStr;
	encodeStr = (unsigned char*)malloc((bitCount / 8 + 1) * sizeof(unsigned char));
	for (int i = 0; i < (bitCount / 8 + 1); i++) {
		*(encodeStr + i) = 0;
	}

	int index = 0;
	int step = 0;
	//遍历源字符串
	for (int i = 0; i < str.length(); i++) {
		//对于每个编码长度不一致,需要一位一位的存储
		for (int j = 0; j < w_map[str[i]].bit; j++) {
			//取出第j位编码,并给新字符串赋值
			unsigned char d = ((w_map[str[i]].code & (128 >> j))) > 0 ? 1 : 0;
			*(encodeStr + index) ^= ((128 * d) >> step);
			
			cout << (d&&(128>>j));
			step++;
			if (step == 8) {
				step = 0;
				index++;
			}
		}
	}
	//给结尾加'\0'
	for (int j = 0; j < w_map[0].bit; j++) {
		unsigned char d = ((w_map[0].code & (128 >> j))) > 0 ? 1 : 0;
		*(encodeStr + index) ^= ((128 * d) >> step);
		cout << (d && (128 >> j));
		step++;
		if (step == 8) {
			step = 0;
			index++;
		}
	}

	double encodeRate = (double)index / (double)str.length();
	cout << endl << endl;
	cout << "压缩率=" << encodeRate * 100 << "%" << endl << endl;

	//解码
	cout << "解码:" << endl;
	index = 0;
	step = 0;
	char ch;
	do {
		getDecode(ch, encodeStr, index, step, huffmanTree);
		cout << ch;
	} while (ch != 0);
	cout << endl;
	
	return 0;
}

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值