哈夫曼编码C++实现

  • Post author:
  • Post category:其他


我也是初识数据结构,本来这一个题目在本站上有许多的解决办法,但是似乎使用的方法就是链表居多,而且可能有点也有点难以理解。下面代码绝对适合像我这样的小白,但是有的问题还是没有解决,就是没怎么去考虑算法结构了,可能复杂度就有点不合人意,但是能跑起来不就是小白最大的心愿吗,代码如下:

#include<iostream>
#include<string>

using namespace std;

const int n = 26;		//定义编码字符个数
char ch[n];		//定义字符存储数组
int w[n];			//定义字符权重存储数组

//定义一个结构体,用作结点信息存储
struct ElemType {
	string code="";		//用来存储该字符的哈夫曼编码
	char data;		//用来存储叶子节点的字符
	int weight;		//假设权值为整数,用来存储叶子结点的权重
	int parent, lchild, rchild;		//用来存储父节点,以及左右孩子结点
	int index = -1;//用来存储原来结构体数组下标,以便于后面给i1,i2赋值
	int LR;	//用来唯一标记该结点是左孩子还是右孩子
};

void Select(ElemType huffTree[], int &i1, int &i2) {		//选择排序,以便于通过每个根节点的权重来获取两个权重最小的根节点下标志
	int count = 0;	//用来计数,方便后边给i1和i2赋值
	ElemType reserve[2 * n - 1];
	for (int i = 0; i < 2 * n - 1; i++) {		//将结构体数组的元素下标初始化
		huffTree[i].index = i;	//将结构体里面的index给初始化,防止排序过后顺序变化而导致获取的原来下标不是之前的数组小标
		reserve[i] = huffTree[i];//同时将reserve[i]用来暂时保存传入的哈夫曼数,以便于后边将这一个给赋值回来,
	}
	for (int i = 0; i < 2 * n - 1; i++) {		//使用冒泡排序对数组通过权重进行从小到大排序
		for (int j = 0; j < 2 * n - 1 - i; j++) {
			if (huffTree[j].weight > huffTree[j + 1].weight) {
				ElemType temp = huffTree[j + 1];
				huffTree[j + 1] = huffTree[j];
				huffTree[j] = temp;
			}
		}
	}
	for (int i = 0; i < 2 * n - 1; i++) {	//遍历huffTree数组,当排好了序的数组遍历到第一个结构体的parent=-1时候将其赋值给i1,之后小中断此循环,之后在进行相似操作,以获取i2
		if (count == 0 && huffTree[i].parent == -1) {		//定义count方便用来获取权重最小的和倒数第二小的结点
			i1 = huffTree[i].index;
			count = 1;
			continue;	//找到第一个之后暂时终止程序,以防两个最小的被赋值为同一个下标
		}
		if (count == 1 && huffTree[i].parent == -1) {
			i2 = huffTree[i].index;
			break;		//找到下标后就可以中断
		}
	}
	//排序过后将haffmanTree恢复原来顺序
	for (int i = 0; i < 2*n-1; i++) {
		huffTree[i] = reserve[i];
	}
}

void input(char ch[],int w[]) {
	cout << "请输入" << n << "个字符:" << endl;
	for (int i = 0; i < n; i++) {
		cin >> ch[i];
	}
	cout << "请输入每个字符对应的权重:" << endl;
	for (int i = 0; i < n; i++) {
		cin >> w[i];
	}
	cout << endl;
}

void createHuffmanTree(ElemType huffTree[], int w[], char ch[]) {
	int i, k, i1, i2;//使用i1和i2用来存储权值权值最小的两个根节点
	cout << endl;
	for (i = 0; i < 2 * n - 1; i++) {	//刚开始所有结点设置为没有双亲和孩子,由于有n个叶子结点就有2*n-1个节点,所以创建创建2*n-1个结点用来存储
		huffTree[i].parent = -1;//指向-1表示没有指向任何一个结点
		huffTree[i].lchild = huffTree[i].rchild = -1;
		huffTree[i].weight = 0x7fffffff;	//权重赋初值为无穷大,以便于后边排序从而寻找i1和i2
		huffTree[i].data = '\0';//给所有的结构体的字符赋值为空字符
	}
	for (i = 0; i < n; i++) {	//储存叶子结点的权值和对应的字符
		huffTree[i].weight = w[i];
		huffTree[i].data = ch[i];
	}
	for (k = n; k < 2 * n - 1; k++) {		//进行n-1次合并,至于为什么是n-1次,这是由于每一次合并都会产生一个新的结点,而除了叶子结点外所有的结点(n-1个)全是合并而来,所以就要进行n-1次合并
		Select(huffTree, i1, i2);		//权值最小的根节点下标为i1和i2
		huffTree[k].weight = huffTree[i1].weight + huffTree[i2].weight;	//新建立的结点权重就是两个子节点权重之和
		huffTree[i1].parent = huffTree[i2].parent = k;		//设置父索引是k
		huffTree[k].lchild = i1; huffTree[k].rchild = i2;	//设置左子索引是i1,右子索引是i2
		huffTree[i1].LR = 0; huffTree[i2].LR = 1;		//用来唯一的表示是左孩子还是右孩子
		cout << "第" << k - n + 1 << "次结点合并权值最小的两个根节点下标:";
		cout << i1 << "和" << i2 << endl;
	}
}

void huffTreeStruct(ElemType huffTree[]) {
	cout << "\n哈夫曼树结构:" << endl;
	cout << "下标   " << "权重   " << "父索引  " << "左子索引 " << "右子索引 " << "字符   " << endl;
	for (int i = 0; i < 2 * n - 1; i++) {
		cout << i << "\t" << huffTree[i].weight << "\t" << huffTree[i].parent << "\t" << huffTree[i].lchild << "\t" << huffTree[i].rchild << "\t  " << huffTree[i].data << endl;
	}
	cout << endl;
}

//根据权重来实现哈夫曼编码
void EnHuffmanCode(ElemType huffTree[]) {
	for (int i = 0; i < n; i++) {	//有n个叶子结点,就要进行n次编码,左子树编码为0,右子树编码为1的规则
		int j = i;		//利用j来存储i以便于后面不至于改变i的值
		while (huffTree[i].parent != -1) {		//循环至根节点停止
			if (huffTree[i].LR == 0) {	//如果该叶子结点的索引等于他父节点的左孩子的索引,也就是判断该结点是他父节点的左孩子,就给编码前面加上"0"
				huffTree[j].code = "0" + huffTree[j].code;		//如果是左孩子就在前面添加上"0"字符
				i = huffTree[i].parent;		//将i用父节点的下标代替
			}
			if (huffTree[i].LR == 1) {	//如果该叶子结点的索引等于他父节点的右孩子的索引,也就是判断该结点是他父节点的右孩子,就给编码前面加上"1"
				huffTree[j].code = "1" + huffTree[j].code;
				i = huffTree[i].parent;		//将i用父节点的下标代替
			}
		}
		i = j;	//将保存了i的j赋值给i
	}
}

void printCode(ElemType huffTree[]) {
	cout << "对输入字符的哈夫曼编码:" << endl;
	for (int i = 0; i < n; i++) {
		cout << huffTree[i].data<<"的编码是:"<<huffTree[i].code << endl;
	}
}

int main() {
	input(ch,w);
	cout << "------------------结果------------------" << endl;
	ElemType huffTree[2 * n];
	createHuffmanTree(huffTree, w, ch);
	EnHuffmanCode(huffTree);
	huffTreeStruct(huffTree);
	printCode(huffTree);
	return 0;
}

问题在于,这一个不是一个可变的数组(只能通过改程序顶部那一个n的取值来解决了),还有就是这一个复杂度有点高,还有就是没有分文件写和有关类的定义.若有问题欢迎大佬指正



版权声明:本文为qq_56715530原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。