哈工大数据结构实验2-树形结构及其应用

该实验旨在通过哈夫曼树实现文本的字符和单词压缩编码,涉及二叉和多叉哈夫曼树的构建、编码、解码以及压缩率计算。实验中,首先从文件中读取字符频率,构建哈夫曼树,然后生成哈夫曼编码表,对文本进行编码并压缩。此外,还探讨了利用堆结构优化的编码算法以及基于单词的压缩方法,对比了不同编码方式的压缩效果。实验结果展示了压缩率和解码后的文本,证明了哈夫曼编码在文本压缩中的有效性。
摘要由CSDN通过智能技术生成

本文仅供参考,严禁抄袭!

实验目的

利用树形结构实现对文本的哈夫曼编码及译码,包括对字符的编码译码和对单词的编码译码,在此过程中熟练掌握树形结构的应用。

实验要求及实验环境

实验要求:

  1. 从文件中读入任意一篇英文文本文件,分别统计英文文本文件中各字符(包
    括标点符号和空格)的使用频率;
  2. 根据已统计的字符使用频率构造哈夫曼编码树,并给出每个字符的哈夫曼编
    码(字符集的哈夫曼编码表);
  3. 将文本文件利用哈夫曼树进行编码,存储成压缩文件(哈夫曼编码文件);
  4. 计算哈夫曼编码文件的压缩率;
  5. 将哈夫曼编码文件译码为文本文件,并与原文件进行比较。
    以下可以不做,供思考,做了可以适当加分
  6. 能否利用堆结构,优化的哈夫曼编码算法。
  7. 上述 1-5 的编码和译码是基于字符的压缩,考虑基于单词的压缩,完成上述
    工作,讨论并比较压缩效果。
  8. 上述 1-5 的编码是二进制的编码,可以采用 K 叉的哈夫曼树完成上述工作,
    实现“K 进制”的编码和译码,并与二进制的编码和译码进行比较。
    实验环境:
    Visual Studio 2019;Windows 10

设计思想(本程序中的用到的所有数据类型的定义,主程序的流程图及各程序模块之间的调用关系)

数据类型:

存储读入字符及其频率的数据结构

  1. 逻辑设计:线性表
  2. 物理设计:结构体数组(Huffnode),每个节点由存储字符的ch和存储频率的freq组成。

存储字符哈夫曼树的数据结构

  1. 逻辑设计:二叉树
  2. 物理设计:静态三叉链表(HTnode):一个节点中存储weight(频率)、parent(父节点)、lchild(左子节点)、rchild(右子节点)、ch(字符)。
  3. 操作:Selectmin():选出权值最小的节点

存储字符哈夫曼编码表的数据结构

  1. 逻辑设计:线性表
  2. 物理设计:结构体数组(HuffList),每个节点由存储字符的ch和存储0、1串的s组成。

存储单词哈夫曼树的数据结构

  1. 逻辑设计:二叉树
  2. 物理设计:静态三叉链表(HTnodeWord),每个节点由weight(频率)、parent(父节点下标)、lchild(左子节点下标)、rchild(右子节点下标)、word(单词)组成。
    操作:SelectWordmin():选出权值最小的节点

存储单词哈夫曼编码表的数据结构

  1. 逻辑设计:线性表
  2. 物理设计:结构体数组(HuffListWord),每个节点由word(单词)和s(存储单词对应的0、1编码)组成。

存储k叉哈夫曼树的数据结构

  1. 逻辑设计:k叉树
  2. 物理设计:静态k+1叉链表(HTKnode),每个节点由weight(频率)、ch(存储字符)、parent(父节点下标)、child[](子节点们的下标)组成。

存储堆的数据结构

  1. 逻辑设计:二叉树
  2. 物理设计:结构体数组,数组的每个节点由weight(权值)和key(在原数组中的下标)组成。
  3. 操作:Initial():初始化堆;DeleteMin():删除堆中最小元素;
    MakeNullHeap():将堆置空;HeapEmpty():堆是否为空;HeapFull():堆是否满

流程图

在这里插入图片描述

调用关系

  1. CreateHuffTree(创建哈夫曼树)函数调用了Selectmin(选择weight最小的两个节点);
  2. DeleteMin(删除堆中最小元素)函数调用了HeapEmpty(判断堆是否为空)函数;
  3. Insert(更新堆中的最小节点)函数调用了DeleteMin(删除最小节点),HeapFull(判断堆是否已满)函数;
  4. CreateHuffTreebyHeap(利用堆结构创建二叉树)函数调用了Initial(初始化堆)和Insert(更新堆中最小节点)函数;
  5. CreateHuffWordTree(创建基于单词的哈夫曼树)函数调用了SelectminWord(选择weight最小的两个节点)函数;
  6. InsertKHeap(更新堆中最小节点)函数调用了HeapEmpty(判断堆是否为空),HeapFull(判断堆是否为满),DeleteMin(删除最小节点)函数;
  7. CreateHuffKTreebyHeap(利用堆结构创建k叉树)函数调用了InitialKTree(初始化堆)和InsertKTree(更新堆中最小节点)函数;

测试结果

测试样例1

输入:American Standard Code for Information Interchange
输出:
在这里插入图片描述在这里插入图片描述
二叉哈夫曼字符编码:111011101101111001101111100000010001001100011100010010100000011010010111010110110101111010011011101001010110011000110111010011011000001111011111011000101100110001111111001110001110000001001110011111
二叉哈夫曼单词编码:
101101110101001100100101000
14叉哈夫曼编码:43484c04946132444a134b104b2424d4b4c2454d02473454d04814a494d324734a4c0464013414c

测试样例2

输入:800词左右的文章
输出:
在这里插入图片描述
在这里插入图片描述

源代码

#include<iostream>
#include<fstream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#define HeapMaxSize 100
using namespace std;
typedef struct {
	char ch;
	int freq;
}Huffnode;//存储刚读入时的字符
typedef struct {
	int weight;
	int lchild;
	int rchild;
	int parent;
	char ch;
}HTnode;//字符的哈夫曼树节点
typedef struct {
	int weight;
	int lchild;
	int rchild;
	int parent;
	string word;
}HTnodeWord;//单词的哈夫曼树节点
typedef struct {
	char ch;
	string s;
}HuffList;//存储字符的哈夫曼编码
typedef struct {
	string word;
	string s;
}HuffListWord;//存储单词的哈夫曼编码表
typedef struct {
	char ch;
	string s;
}Huffman;//按ASCII码顺序存储字符的哈夫曼编码表
typedef struct {
	int weight, parent, child[16];
	char ch;
}HTKnode;//存储字符的k叉哈夫曼树节点
int Readin(vector<Huffnode>& asc, int& sum)//从文件中读入字符,并初始化weight,最后按weight从大到小排序,返回值为weight非0的字符数目
{
	ifstream in("text.txt");
	string s;//存储的是从文件中读入的串
	for (int j = 0; j < 127; j++)
	{
		asc[j].ch = j;
		asc[j].freq = 0;
	}
	getline(in, s);
	for (int i = 0; i < s.length(); i++)
	{
		asc[s[i]].freq++;//按ASCII码索引
		sum++;
	}
	in.close();
	int k = 0, l = 0, max;
	Huffnode temp;
	for (k = 0; k < asc.size() - 1; k++)//这里按weight从小到大排序,采用选择排序算法
	{
		max = k;
		for (l = k + 1; l < asc.size(); l++)
		{
			if (asc[l].freq > asc[max].freq)
			{
				max = l;
			}
		}
		temp = asc[k];
		asc[k] = asc[max];
		asc[max] = temp;
	}
	int m = 0;
	while (asc[m++].freq != 0);//计算weight不为0的字符个数
	return m - 1;
}
void Selectmin(vector<HTnode> tr, int& p1, int& p2, int n)//在哈夫曼树中选weight最小的两个,复杂度为O(n)
{
	int i, j;
	for (i = 0; i < n; i++)
	{
		if (tr[i].parent == -1)
		{
			p1 = i;
			break;
		}
	}
	for (j = i + 1; j < n; j++)
	{
		if (tr[j].parent == -1)
		{
			p2 = j;
			break;
		}
	}
	for (i = 0; i < n; i++)
	{
		if ((tr[p1].weight > tr[i].weight) && (tr[i].parent == -1) && (p2 != i))
		{
			p1 = i;
		}
	}
	for (j = 0; j < n; j++)
	{
		if ((tr[p2].weight > tr[j].weight) && (tr[j].parent == -1) && (p1 != j))
		{
			p2 = j;
		}
	}
}
void SelectminWord(vector<HTnodeWord> tr, int& p1, int& p2, int n)//在哈夫曼树中选择weight最小的两个单词,复杂度同上
{
	int i, j;
	for (i = 0; i < n; i++)
	{
		if (tr[i].parent == -1)
		{
			p1 = i;
			break;
		}
	}
	for (j = i + 1; j < n; j++)
	{
		if (tr[j].parent == -1)
		{
			p2 = j;
			break;
		}
	}
	for (i = 0; i < n; i++)
	{
		if ((tr[p1].weight > tr[i].weight) && (tr[i].parent == -1) && (p2 != i))
		{
			p1 = i;
		}
	}
	for (j = 0; j < n; j++)
	{
		if ((tr[p2].weight > tr[j].weight) && (tr[j].parent == -1) && (p1 != j))
		{
			p2 = j;
		}
	}
}
void CreateHuffTree(int num, vector<HTnode>& tr, vector<Huffnode>asc, int sum)//创建二叉哈夫曼树,复杂度为O(num),num为字符数(重复的算一个)
{
	HTnode tree;
	int i, j = num - 1, p1 = 0, p2 = 1;
	for (i = 0; i < num; i++)//先把所有叶子节点填入二叉树,左右儿子和父亲均赋值为-1
	{
		tree.ch = asc[j].ch;
		tree.weight = asc[j].freq;
		tree.lchild = -1;
		tree.parent = -1;
		tree.rchild = -1;
		tr.push_back(tree);
		j--;
	}
	for (i = num; i < 2 * num - 1; i++)//再做合并节点的操作
	{
		Selectmin(tr, p1, p2, i);//选择weight最小的两个节点
		tr[p1].parent = i;
		tr[p2].parent = i;
		tree.lchild = p1;
		tree.rchild = p2;
		tree.weight = tr[p1].weight + tr[p2].weight;
		tr.push_back(tree);
	}
}
bool SortCh(HuffList a, HuffList b)//比较字符的大小,此函数用于之后的排序
{
	return a.ch < b.ch;
}
void HuffCode(vector<HTnode>tr, int num, vector<HuffList>& huffman, vector<HuffList>& huff1)//按哈夫曼树对所有字符进行编码,时间复杂度为O(num*h),h为哈夫曼树高度
{
	int i, j, parent;
	HuffList huff;
	for (i = 0; i < num; i++)
	{
		huff.ch = tr[i].ch;
		huff.s = "";//用于存储编码
		j = i;
		while (1)//遍历哈夫曼树一支,类似深搜
		{
			parent = tr[j].parent;
			if (parent == -1)
				break;
			if (tr[parent].lchild == j)
				huff.s += "0";
			else if (tr[parent].rchild == j)
				huff.s += "1";
			j = parent;
		}
		reverse(huff.s.begin(), huff.s.end());//反转编码
		huffman.push_back(huff);
	}
	huff1 = huffman;
	sort(huffman.begin(), huffman.end(), SortCh);
}
void FileHuff(vector<HuffList> hufflist, int num, Huffman huff[])//将文本文件转为哈夫曼编码,并将编码写入文件"huffmancode.txt"
{
	string str;
	ifstream in("text.txt");
	ofstream out("huffmancode.txt");
	getline(in, str);
	for (int i = 0; i < num; i++)
	{
		huff[hufflist[i].ch].s = hufflist[i].s;
		huff[hufflist[i].ch].ch = hufflist[i].ch;
	}
	for (int i = 0; i < str.length(); i++)
	{
		out << huff[str[i]].s;
	}
	out << endl;
	in.close();
	out.close();
}
void ComRate(vector<HuffList> hufflist, vector<HTnode> huffnode, int sum, int num)//计算压缩率,这里定义的压缩率为1-HufLength/EqlLength,其中HufLength为哈夫曼编码的平均码长,EqlLength为等长二进制码的码长
{
	double length = 0, rate;
	int bit = 0, numbe = num, j = num - 1;
	while (num != 0)//计算等长二进制码的码长
	{
		num = num >> 1;//位运算,右移一位
		bit++;
	}
	for (int i = 0; i < numbe; i++)
	{
		length += hufflist[i].s.length() * (huffnode[i].weight / double(sum));
	}
	rate = (1 - length / bit) * 100;
	cout << "平均位宽压缩率为:" << rate << "%" << endl;
}
void ComRatePlus(int sum)//计算压缩率,这里压缩率的定义为此文本按哈夫曼编码所需的字节数与按ASCII所需字节数之比
{
	int binsum;
	string s;
	ifstream in("huffmancode.txt");
	getline(in, s);
	binsum = s.length();
	in.close();
	cout << "压缩率为" << double(binsum) * 100 / (sum * 8) << "%" << endl;
}
void Decode(vector<HTnode>hufftree, int sum, int num)//为哈夫曼编码文件解码,复杂度为O(sum*h),sum为总的字符个数(重复也算),h为哈夫曼树高
{
	string s;
	int j = 0, child;
	ifstream in("huffmancode.txt");
	ofstream out("decodetext.txt");
	getline(in, s);
	for (int i = 0; i < sum; i++)
	{
		child = 2 * num - 2;
		while (1)//按文本中存储的哈夫曼编码逐步在哈夫曼树上查找,直至找到
		{
			if (s[j] == '0')
			{
				child = hufftree[child].lchild;
				j++;
			}
			else if (s[j] == '1')
			{
				child = hufftree[child].rchild;
				j++;
			}
			if (hufftree[child].lchild == -1 && hufftree[child].rchild == -1)
			{
				out << hufftree[child].ch;
				break;
			}
		}
	}
	out.close();
	in.close();
}
typedef struct {
	int weight, key;
}Elementype;//用于堆的一个数据类型
typedef struct {
	Elementype elements[HeapMaxSize];
	int n;
}HEAP;//堆的定义
void MakeNullHeap(HEAP& heap)//将堆置空
{
	heap.n = 0;
}
bool HeapFull(HEAP heap)
{
	return (heap.n == HeapMaxSize - 1);
}//判断堆是否为满
bool HeapEmpty(HEAP heap)//判断堆是否为空
{
	return (!heap.n);
}
void Initial(HEAP& heap, int num, vector<HTnode>tree)//将堆初始化,即先把哈夫曼树的叶节点的weight和key先放入,堆为最小堆
{
	int j;
	for (int i = 0; i < num; i++)
	{
		j = heap.n + 1;
		while ((j != 1) && (tree[i].weight < heap.elements[j / 2].weight))
		{
			heap.elements[j] = heap.elements[j / 2];
			j /= 2;
		}
		heap.elements[j].weight = tree[i].weight;
		heap.elements[j].key = i;
		heap.n++;
	}
}
void DeleteMin(HEAP& heap)//删除最小元素
{
	Elementype temp;
	int parent = 1, child = 2;
	if (!HeapEmpty(heap))
	{
		temp = heap.elements[heap.n--];
		while (child <= heap.n)
		{
			if ((child < heap.n) && (heap.elements[child].weight > heap.elements[child + 1].weight))
			{
				child++;
			}
			if (temp.weight <= heap.elements[child].weight)
				break;
			heap.elements[parent] = heap.elements[child];
			parent = child;
			child *= 2;
		}
		heap.elements[parent] = temp;
	}
}
void Insert(HEAP& heap, int num, vector<HTnode>tree, int& p1, int& p2, int i)//更新堆中最小节点
{
	int summary, weight;
	p1 = heap.elements[1].key;
	weight = heap.elements[1].weight;
	DeleteMin(heap);
	p2 = heap.elements[1].key;
	summary = weight + heap.elements[1].weight;
	DeleteMin(heap);
	int j;
	if (!HeapFull(heap))
	{
		j = heap.n + 1;
		while ((j != 1) && (summary < heap.elements[j / 2].weight))
		{
			heap.elements[j] = heap.elements[j / 2];
			j /= 2;
		}
		heap.elements[j].weight = summary;
		heap.elements[j].key = i;
		heap.n++;
	}
}
void CreateHuffTreebyHeap(int num, vector<HTnode>& tr, vector<Huffnode>asc, int sum, HEAP& heap)//通过堆建立哈夫曼树,O(log(2*num)*num)
{
	HTnode tree;
	int i, j = num - 1, p1 = 0, p2 = 1;
	for (i = 0; i < num; i++)
	{
		tree.ch = asc[j].ch;
		tree.weight = asc[j].freq;
		tree.lchild = -1;
		tree.parent = -1;
		tree.rchild = -1;
		tr.push_back(tree);
		j--;
	}
	Initial(heap, num, tr);
	for (i = num; i < 2 * num - 1; i++)
	{
		Insert(heap, num, tr, p1, p2, i);
		tr[p1].parent = i;
		tr[p2].parent = i;
		tree.lchild = p1;
		tree.rchild = p2;
		tree.weight = tr[p1].weight + tr[p2].weight;
		tr.push_back(tree);
	}
}
void ReadinWord(map<string, int>& HuffnodeWord, int& sumword, set<string>& word)//读入单词,规则是:单词直接读入,符号和数字单个读入
{
	string s, words = "";
	int i = 0;
	ifstream in("text.txt");
	getline(in, s);
	while (s[i] != '\0')
	{
		words = "";
		if (s[i] >= 'A' && s[i] <= 'z')
		{
			while (s[i] >= 'A' && s[i] <= 'z')
			{
				words += s[i];
				i++;
			}
		}
		else if (s[i] < 'A' || s[i]>'z')
		{
			words += s[i];
			i++;
		}

		if (HuffnodeWord.find(words) != HuffnodeWord.end())
		{
			HuffnodeWord[words]++;
		}
		else
		{
			HuffnodeWord.insert(pair<string, int>(words, 1));
		}
		word.insert(words);
		sumword++;
	}
}
void CreateHuffWordTree(map<string, int>HuffnodeWord, set<string>word, vector<HTnodeWord>& tr)//建立基于单词的哈夫曼树
{
	HTnodeWord tree;
	int i, p1 = 0, p2 = 1;
	for (auto tmp : word)
	{
		tree.word = tmp;
		tree.weight = HuffnodeWord[tmp];
		tree.lchild = -1;
		tree.parent = -1;
		tree.rchild = -1;
		tr.push_back(tree);
	}
	for (i = word.size(); i < 2 * word.size() - 1; i++)
	{
		SelectminWord(tr, p1, p2, i);
		tr[p1].parent = i;
		tr[p2].parent = i;
		tree.lchild = p1;
		tree.rchild = p2;
		tree.weight = tr[p1].weight + tr[p2].weight;
		tr.push_back(tree);
	}
}
void HuffCodeWord(vector<HTnodeWord>tr, vector<HuffListWord>& huffman, set<string>words)//将单词进行哈夫曼编码
{
	int i, j, parent;
	HuffListWord huff;
	for (i = 0; i < words.size(); i++)
	{
		huff.word = tr[i].word;
		huff.s = "";
		j = i;
		while (1)
		{
			parent = tr[j].parent;
			if (parent == -1)
				break;
			if (tr[parent].lchild == j)
				huff.s += "0";
			else if (tr[parent].rchild == j)
				huff.s += "1";
			j = parent;
		}
		reverse(huff.s.begin(), huff.s.end());
		huffman.push_back(huff);
	}
}
void FileHuffWord(vector<HuffListWord> hufflistword, set<string>wordlist)//将对单词的编码按文本顺序写入文件
{
	string str;
	string s, words = "";
	int i = 0;
	ifstream in("text.txt");
	ofstream out("huffmanwordcode.txt");
	getline(in, s);
	while (s[i] != '\0')
	{
		words = "";
		if (s[i] >= 'A' && s[i] <= 'z')
		{
			while (s[i] >= 'A' && s[i] <= 'z')
			{
				words += s[i];
				i++;
			}
		}
		else if (s[i] < 'A' || s[i]>'z')
		{
			words += s[i];
			i++;
		}
		for (int j = 0; j < hufflistword.size(); j++)
		{
			if (words == hufflistword[j].word)
				out << hufflistword[j].s;
		}
	}
	out << endl;
	out.close();
	in.close();
}
void ComRateWord(int sum)//计算基于单词的压缩率
{
	int binsum;
	string s;
	ifstream in("huffmanwordcode.txt");
	getline(in, s);
	binsum = s.length();
	in.close();
	cout << "压缩率为" << double(binsum) * 100 / (sum * 8) << "%" << endl;
}
void DecodeWord(vector<HTnodeWord>hufftree, int sumword, set<string>wordlist)
{
	string s;
	int j = 0, child;
	ifstream in("huffmanwordcode.txt");
	ofstream out("decodewordtext.txt");
	getline(in, s);
	for (int i = 0; i < sumword; i++)
	{
		child = 2 * wordlist.size() - 2;
		while (1)
		{
			if (s[j] == '0')
			{
				child = hufftree[child].lchild;
				j++;
			}
			else if (s[j] == '1')
			{
				child = hufftree[child].rchild;
				j++;
			}
			if (hufftree[child].lchild == -1 && hufftree[child].rchild == -1)
			{
				out << hufftree[child].word;
				break;
			}
		}
	}
	out.close();
	in.close();
}
void InitialKTree(HEAP& heap, int num, vector<HTKnode>tree)
{
	int j;
	for (int i = 0; i < num; i++)
	{
		j = heap.n + 1;
		while ((j != 1) && (tree[i].weight < heap.elements[j / 2].weight))
		{
			heap.elements[j] = heap.elements[j / 2];
			j /= 2;
		}
		heap.elements[j].weight = tree[i].weight;
		heap.elements[j].key = i;
		heap.n++;
	}
}
void InsertKHeap(HEAP& heap, vector<HTKnode>tree, int key[], int i, int k)
{
	int sumweight = 0;
	for (int i = 0; i < k; i++)
	{
		if (!HeapEmpty(heap))
		{
			key[i] = heap.elements[1].key;
			sumweight += heap.elements[1].weight;
		}
		else
		{
			key[i] = -1;
			sumweight += 0;
		}
		DeleteMin(heap);
	}
	int j;
	if (!HeapFull(heap))
	{
		j = heap.n + 1;
		while ((j != 1) && (sumweight < heap.elements[j / 2].weight))
		{
			heap.elements[j] = heap.elements[j / 2];
			j /= 2;
		}
		heap.elements[j].weight = sumweight;
		heap.elements[j].key = i;
		heap.n++;
	}
}
void CreateHuffKTreebyHeap(int num, vector<HTKnode>& tr, vector<Huffnode>asc, HEAP& heap, int k)//创建k叉树,O((list-num-add)*log(all))
{
	HTKnode tree;
	int key[16] = { -1 };
	int add = 0, m = num, n;
	while (m > k)
	{
		n = m % k;
		m /= k;
		m += n;
	}
	add = k - m;//add为要补的节点数
	int i, j = num - 1;
	for (i = 0; i < num; i++)
	{
		tree.ch = asc[j].ch;
		tree.weight = asc[j].freq;
		for (int l = 0; l < 16; l++)
		{
			tree.child[l] = -1;
		}
		tree.parent = -1;
		tr.push_back(tree);
		j--;
	}
	InitialKTree(heap, num, tr);
	for (i = num; i < (k * (num + add) - 1) / (k - 1) - add; i++)
	{
		InsertKHeap(heap, tr, key, i, k);
		tree.weight = 0;
		for (int l = 0; l < k; l++)
		{
			if (key[l] == -1)
				continue;
			tr[key[l]].parent = i;
			tree.child[l] = key[l];
			tree.weight += tr[key[l]].weight;
		}
		tr.push_back(tree);
	}
}
void HuffKCode(vector<HTKnode>tr, int num, vector<HuffList>& huffman, int k)//利用k叉哈夫曼树给字符编码,O(num*h)
{
	int i, j, parent, l;
	HuffList huff;
	char code[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };//存储编码
	for (i = 0; i < num; i++)
	{
		huff.ch = tr[i].ch;
		huff.s = "";
		j = i;
		while (1)
		{
			parent = tr[j].parent;
			if (parent == -1)
				break;
			for (l = 0; l < k; l++)
			{
				if (tr[parent].child[l] == j)
					break;
			}
			huff.s += code[l];
			j = parent;
		}
		reverse(huff.s.begin(), huff.s.end());
		huffman.push_back(huff);
	}
}
void FileKHuff(vector<HuffList> hufflist, int num, Huffman huff[])//将文本用k叉哈夫曼编码表编码并写入文件
{
	string str;
	ifstream in("text.txt");
	ofstream out("khuffmancode.txt");
	getline(in, str);
	for (int i = 0; i < num; i++)
	{
		huff[hufflist[i].ch].s = hufflist[i].s;
		huff[hufflist[i].ch].ch = hufflist[i].ch;
	}
	for (int i = 0; i < str.length(); i++)
	{
		out << huff[str[i]].s;
	}
	out << endl;
	in.close();
	out.close();
}
void KDecode(vector<HTKnode>hufftree, int sum, int num, int k)//从文件中读入编码并解码
{
	string s;
	int j = 0, child, l, flag = 0;
	char code[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
	ifstream in("khuffmancode.txt");
	ofstream out("kdecodetext.txt");
	getline(in, s);
	for (int i = 0; i < sum; i++)
	{
		child = hufftree.size() - 1;
		while (1)
		{
			for (l = 0; l < k; l++)
			{
				if (s[j] == code[l])
					break;
			}
			child = hufftree[child].child[l];
			j++;
			flag = 0;
			for (int m = 0; m < k; m++)
			{
				if (hufftree[child].child[m] != -1)
				{
					flag = 1;
					break;
				}
			}
			if (flag == 0)
			{
				out << hufftree[child].ch;
				break;
			}
		}
	}
	out.close();
	in.close();
}
void KComRatePlus(int sum, int k)//计算k叉哈夫曼树编码的压缩率
{
	int binsum;
	string s;
	int bit = 0, b = k;
	while (k != 0)
	{
		k = k >> 1;//位运算,右移一位
		bit++;
	}
	ifstream in("khuffmancode.txt");
	getline(in, s);
	binsum = s.length();
	in.close();
	if (b != 2)
		cout << "压缩率为" << double(binsum * bit) * 100 / (sum * 8) << "%" << endl;
	else if (b == 2)
		cout << "压缩率为" << double(binsum) * 100 / (sum * 8) << "%" << endl;
}
int main()
{
	vector<Huffnode> asc(127);
	int sum = 0;
	int num;
	HEAP heap;
	MakeNullHeap(heap);
	num = Readin(asc, sum);
	/*for (int i = 0; i < num; i++)
	{
		printf("%c:%d\n", asc[i].ch, asc[i].freq);
	}*/
	vector<HTnode> tree;
	CreateHuffTreebyHeap(num, tree, asc, sum, heap);
	//CreateHuffTree(num, tree, asc, sum);
	/*for (int i = 0; i < 2 * num - 1; i++)
	{
		printf("%3d  %3d  %3d  %3d\n", tree[i].weight, tree[i].parent, tree[i].lchild, tree[i].rchild);
	}*/
	vector<HuffList> huff, huffcopy;
	HuffCode(tree, num, huff, huffcopy);
	cout << "二叉哈夫曼树字符编码:" << endl;
	for (int i = 0; i < num; i++)
	{
		cout << huff[i].ch << ":" << huff[i].s << endl;
	}
	Huffman huffman[127];
	FileHuff(huffcopy, num, huffman);
	ComRate(huffcopy, tree, sum, num);
	ComRatePlus(sum);
	Decode(tree, sum, num);
	/*for (int i = 1; i <=  num; i++)
	{
		cout << "weight:" << heap.elements[i].weight << ";key:" << heap.elements[i].key << endl ;
	}*/
	map<string, int> HuffnodeWord;//基于单词的压缩
	int sumword = 0;
	set<string>wordlist;
	vector<HTnodeWord>wordtree;
	ReadinWord(HuffnodeWord, sumword, wordlist);
	cout << endl << "二叉哈夫曼树单词编码:" << endl;
	/*for (auto tmp : wordlist)
	{
		cout << tmp << ":" << HuffnodeWord[tmp] << endl;
	}*/
	CreateHuffWordTree(HuffnodeWord, wordlist, wordtree);
	/*for (int i = 0; i < 2 * wordlist.size() - 1; i++)
	{
		printf("%3d  %3d  %3d  %3d\n", wordtree[i].weight, wordtree[i].parent, wordtree[i].lchild, wordtree[i].rchild);
	}*/
	vector<HuffListWord>hufflistword;
	HuffCodeWord(wordtree, hufflistword, wordlist);
	for (int i = 0; i < wordlist.size(); i++)
	{
		cout << hufflistword[i].word << ":" << hufflistword[i].s << endl;
	}
	FileHuffWord(hufflistword, wordlist);
	ComRateWord(sum);
	DecodeWord(wordtree, sumword, wordlist);
	vector<HTKnode> ktree;
	HEAP kheap;
	MakeNullHeap(kheap);
	int k;
	cout << "请输入k(2<=k<=16):";
	cin >> k;
	if (k > 16 || k < 2)
	{
		cout << "k范围不合规定" << endl;
		exit(0);
	}
	CreateHuffKTreebyHeap(num, ktree, asc, kheap, k);
	/*for (int i = 0; i < ktree.size(); i++)
	{
		printf("%3d %3d ", ktree[i].weight, ktree[i].parent);
		for (int j = 0; j < 16; j++)
		{
			printf("%3d ", ktree[i].child[j]);
		}
		cout << endl;
	}*/
	cout << endl << k << "叉哈夫曼树字符编码:" << endl;
	vector<HuffList> khufflist;
	HuffKCode(ktree, num, khufflist, k);
	for (int i = 0; i < num; i++)
	{
		cout << khufflist[i].ch << ":" << khufflist[i].s << endl;
	}
	FileKHuff(khufflist, num, huffman);
	KComRatePlus(sum, k-1);
	KDecode(ktree, sum, num, k);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值