数据结构课程设计实践--哈夫曼树

1.问题描述

2.需求分析

2.1 功能需求

设计一个哈夫曼的编/译码系统,实现下述功能:

  1. 初始化,从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中;
  2. 编码,利用已经建立好的哈夫曼树(如不在内存里,则从文件hfmTree中的正文进行编码,然后将结果存入文件CodeFile中;
  3. 译码,利用已经建好的哈夫曼将文件CodeFile中的代码进行译码,结果存入文件TextFile中;
  4. 印代码文件,将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中;
  5. 印哈夫曼树,将已在内存中的哈夫曼树以值观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrin中
  6. 实现各个转换操作的源/目文件,均由用户在选择此操作时指定

2.2 界面需求

打印出菜单界面供用户选择,打印出各个字符的编码、需要编码的字符内容、编码结果、需要译码的内容、译码的结果、打印代码文件、以凹入表的形式打印哈夫曼树

2.3 接口需求

初始化哈夫曼、编码、译码、打印代码文件、打印哈夫曼树

3. 概要设计

模块层次结构设计

接口设计

void InitHuffmanTree(HuffmanTree& HT, int n);//初始化哈夫曼树
void DEstroyHuffmanTree(HuffmanTree& HT);//销毁哈夫曼树
int MinVal(HuffmanTree& HT, int i);//在前i个结点中选择parant为-1且weight最小的结点并获得其序号
void Select(HuffmanTree& HT, int i, int& s1, int& s2);//s1为最小的两个值中序号小的那个
void Create(HuffmanTree& HT, int n, char ch[], int weight[]);//建立哈夫曼树
void Display(HuffmanTree HT);//显示哈夫曼树
void PutinHT(HuffmanTree& HT);//哈夫曼树保存到文件夹中
int Getn(const string& filename);//获得文件夹中的叶子结点的个数
void PutoutHT(HuffmanTree& HT, const string& filename, int n);//从文件中读入哈夫曼树
void InitHuffmanCoder(HuffmanCoder& HC, int n);//初始化编码表
void DestroyHuffmanCoder(HuffmanCoder& HC);//销毁编码表
void CreateBook(HuffmanCoder& HC, HuffmanTree& HT);//建立编码表
void Coder(HuffmanCoder& HC, char ch[], string filename);//编码
void Decoder(HuffmanTree& HT, char ch[], string filename);//译码

void GotoXY(int x, int y);//光标位置
char menu();//菜单函数,返回操作
void Initialization(HuffmanTree& HT, int& n);//初始化
void Encoding(HuffmanTree& HT, int n);//编码
void Decoding(HuffmanTree& HT, int n);//译码
void Print();//打印代码文件
void printHuffmanTree(const HuffmanTree& huffmanTree, int root, int level = 0);//打印哈夫曼树
void writeHuffmanTreeToFile(const HuffmanTree& huffmanTree, int root, ofstream& outFile, int level = 0);//将哈夫曼树存入文件夹中
void Tree_printing(HuffmanTree& HT, int n);//印哈夫曼树

界面设计 

菜单设计


    system("cls");
	GotoXY(38, 8);
	printf("欢迎使用哈夫曼编/译码器");
	GotoXY(43, 10);
	printf("I. 初始化");
	GotoXY(43, 12);
	printf("E. 编码");
	GotoXY(43, 14);
	printf("D. 译码");
	GotoXY(43, 16);
	printf("P. 印代码文件");
	GotoXY(43, 18);
	printf("T. 印哈夫曼树");
	GotoXY(43, 20);
	printf("Q. 退出");
	GotoXY(38, 22);
	printf("请输入您需要进行的操作[ ]\b\b");

数据结构设计

//哈夫曼树结点
struct HTnode {
	char ch;
	int weight, parent, lchild, rchild;
};
//哈夫曼树
struct HuffmanTree {
	HTnode* ht;
	int htsize;
	bool flag = false;
};
//字符编码结构
struct HCode {
	char ch;
	char* pstring;
};
//编码表结构
struct HuffmanCoder {
	HCode* hc;
	int hcsize;
};

3. 详细设计

“Huffman.h”

#ifndef _HUFFMAN_H_
#define _HUFFMAN_H_
#include<fstream>
#include <iomanip>
#include<iostream>
#include <ios>

using namespace std;
#define max 10000

struct HTnode {
	char ch;
	int weight, parent, lchild, rchild;
};

struct HuffmanTree {
	HTnode* ht;
	int htsize;
	bool flag = false;
};


void InitHuffmanTree(HuffmanTree& HT, int n)
{
	HT.ht = new HTnode[2 * n - 1];
	HT.htsize = 2 * n - 1;
	HT.flag = true;
}

void DEstroyHuffmanTree(HuffmanTree& HT)
{
	delete[]HT.ht;
	HT.htsize = 0;
}

int MinVal(HuffmanTree& HT, int i)
{
	int j, k=max, min = max;
	for(j=0;j<i;j++)
		if (HT.ht[j].parent == -1 && HT.ht[j].weight < min)
		{
			min = HT.ht[j].weight;
			k = j;
		}
	HT.ht[k].parent = max;
	return k;
}

void Select(HuffmanTree& HT, int i, int& s1, int& s2)
{
	int s;
	s1 = MinVal(HT, i);
	s2 = MinVal(HT, i);
	if (s1 > s2)
	{
		s = s1; 
		s1 = s2;
		s2 = s;
	}
}

//创建哈夫曼树
void Create(HuffmanTree& HT, int n, char ch[], int weight[])
{
	int i, s1, s2;
	if (n > 1)
	{
		for (i = 0; i < n; i++)
		{
			HT.ht[i].ch = ch[i];
			HT.ht[i].weight = weight[i];
			HT.ht[i].parent = -1;
			HT.ht[i].lchild = -1;
			HT.ht[i].rchild = -1;
		}
		for (; i < HT.htsize; ++i)
		{
			Select(HT, i, s1, s2);
			HT.ht[s1].parent = HT.ht[s2].parent = i;
			HT.ht[i].lchild = s1;
			HT.ht[i].rchild = s2;
			HT.ht[i].weight = HT.ht[s1].weight + HT.ht[s2].weight;
			HT.ht[i].parent = -1;
			HT.ht[i].ch = ' ';
		}
	}
	cout <<endl<< "哈夫曼树建毕!" << endl<<endl;
}

//显示哈夫曼树
void Display(HuffmanTree HT)
{
	int i;
	cout << "所建哈夫曼树的静态链表表示如下:" << endl << endl;
	cout << "下标位置" << " 字符 " << "  权值  " << " 左孩子 " << " 右孩子 " << " 双亲 " << endl;
	for (i = 0; i < HT.htsize; i++)
	{
		cout << setw(6) << i << setw(6) << HT.ht[i].ch << setw(8) << HT.ht[i].weight << setw(9) << HT.ht[i].lchild << setw(8) << HT.ht[i].rchild << setw(6) << HT.ht[i].parent << endl;
	}
	cout << endl;
	system("pause");
}

//哈夫曼树保存到文件夹中
void PutinHT(HuffmanTree& HT)
{
	ofstream outfile("hfmTree.txt", ios::in);
	for (int i = 0; i < HT.htsize; i++)
	{
		outfile<< setw(6) << i << setw(6) << HT.ht[i].ch << setw(8) << HT.ht[i].weight << setw(9) << HT.ht[i].lchild << setw(8) << HT.ht[i].rchild << setw(6) << HT.ht[i].parent << endl;
	}
	
	outfile.close();
}

int Getn(const string& filename)
{
	ifstream infile(filename, ios::in);
	if (!infile)
	{
		cerr << "Error opening file: " << filename << endl;
		return -1;
	}

	int a, b, c, d, e;
	char ch;
	int n = 0;
	while (infile >> a >> ch >> b >> c >> d >> e)
	{
		if (c==-1) n++;
	}
	return n;
}

void PutoutHT(HuffmanTree& HT, const string& filename,int n)
{
	ifstream infile(filename, ios::in);

	if (!infile)
	{
		cerr << "Error opening file: " << filename << endl;
		return;
	}


	// 根据确定的 n 值初始化 HuffmanTree
	InitHuffmanTree(HT, n);

	int i = 0;
	int x;

	// 遍历文件以读取数据
	for (int i = 0; i < HT.htsize ; i++)
	{
		
		//fstream obj(filename, ios::in | ios::out);
		//obj >> noskipws;
		if (i < n&&i!=0) {
			infile >> setw(6) >> x >> setw(6) >> HT.ht[i].ch >> setw(8) >> HT.ht[i].weight >> setw(9) >> HT.ht[i].lchild >> setw(8) >> HT.ht[i].rchild >> setw(6) >> HT.ht[i].parent;
			
		}
		else
			infile >> setw(6) >> x  >> HT.ht[i].weight >> setw(9) >> HT.ht[i].lchild >> setw(8) >> HT.ht[i].rchild >> setw(6) >> HT.ht[i].parent;
	}
	HT.ht[0].ch = ' ';
	infile.close();
}


struct HCode {
	char ch;
	char* pstring;
};

struct HuffmanCoder {
	HCode* hc;
	int hcsize;
};

void InitHuffmanCoder(HuffmanCoder& HC, int n)
{
	HC.hc = new HCode[n];
	HC.hcsize = n;
}

void DestroyHuffmanCoder(HuffmanCoder& HC)
{
	for (int i = 0; i < HC.hcsize; i++)
		delete[]HC.hc[i].pstring;
	delete[]HC.hc;
}

void CreateBook(HuffmanCoder& HC, HuffmanTree& HT)
{
	int i, j, c, f, start;
	char* cd = new char[HC.hcsize];
	cd[HC.hcsize - 1] = '\0';

	cout<<"以下是各字符的哈夫曼编码:" << endl << endl;

	for (i = 0; i < HC.hcsize; i++)
	{
		start = HC.hcsize - 1;
		HC.hc[i].ch = HT.ht[i].ch;

		for (c = i, f = HT.ht[i].parent; f != -1; c = f, f = HT.ht[f].parent)
			if (f >= 0 && f < HT.htsize) {
				if (HT.ht[f].lchild == c) {
					cd[--start] = '0';
				}
				else {
					cd[--start] = '1';
				}
			}
			else {
				// 处理异常情况,例如输出错误信息或者中断循环
				cerr << "Error: Invalid index in Huffman tree." << endl;
				break;
			}
				

		HC.hc[i].pstring = new char[HC.hcsize - start];
		cout << "第" << setw(2)<<i + 1 << "个字符" << HT.ht[i].ch << "的编码是:";
		for (j = start; j < HC.hcsize; j++)
		{
			cout << cd[j];
			HC.hc[i].pstring[j - start] = cd[j];
		}
		
		cout << endl;
	}
	cout << endl;
	delete[]cd;
}

void Coder(HuffmanCoder& HC, char ch[],string filename)
{
	ofstream outfile(filename, ios::out);
	for(int i=0;i<strlen(ch);i++)
		for(int j=0;j<HC.hcsize;j++)
			if (ch[i] == HC.hc[j].ch)
			{
				for (int k = 0; k<strlen(HC.hc[j].pstring); k++)
				{
					cout<<HC.hc[j].pstring[k];
					outfile.put(HC.hc[j].pstring[k]);

				}
			}
	outfile.put('\0');
	cout << endl;
	outfile.close();
}

void Decoder(HuffmanTree& HT,char ch[],string filename)
{
	int j(0), i(0), p, pre, root = HT.htsize - 1;

	ofstream outfile(filename, ios::out);
	
	cout << "需译码的二进制电文是:" << endl;
	j = 0;
	while (ch[j])
	{
		cout << ch[j];
		j++;
	}
	cout << endl;
	cout << "译码结果:" << endl;
	pre = -1;
	p = root;
	while (i < strlen(ch))
	{
		while (p != -1)
		{
			if (ch[i] == '0')
			{
				pre = p;
				p = HT.ht[p].lchild;
			}
			else
			{
				pre = p;
				p = HT.ht[p].rchild;
			}
			i++;
		}
		cout << HT.ht[pre].ch;
		outfile.put(HT.ht[pre].ch);
		i--;
		pre = -1;
		p = root;
	}
	cout << endl;
	system("pause");
}
#endif

“main.cpp”

#include<iostream>
#include<Windows.h>
#include<string>
#include<cstring>
#include <cctype>
#include <limits>
#include <sstream>
#include"Huffman.h"

using namespace std;

char ch[256];
int weight[256];

bool initflag = false;


void GotoXY(int x, int y) {
	HANDLE hout;
	COORD cor;
	hout = GetStdHandle(STD_OUTPUT_HANDLE);
	cor.X = x;
	cor.Y = y;
	SetConsoleCursorPosition(hout, cor);
}


char menu()
{
	system("cls");
	GotoXY(38, 8);
	printf("欢迎使用哈夫曼编/译码器");
	GotoXY(43, 10);
	printf("I. 初始化");
	GotoXY(43, 12);
	printf("E. 编码");
	GotoXY(43, 14);
	printf("D. 译码");
	GotoXY(43, 16);
	printf("P. 印代码文件");
	GotoXY(43, 18);
	printf("T. 印哈夫曼树");
	GotoXY(43, 20);
	printf("Q. 退出");
	GotoXY(38, 22);
	printf("请输入您需要进行的操作[ ]\b\b");
	char ch;
	char result='q';
	ch = getchar();
	switch (ch) {
		case 'i': result = 'i'; break;
		case 'I': result = 'i'; break;
		case 'e': result = 'e'; break;
		case 'E': result = 'e'; break;
		case 'd': result = 'd'; break;
		case 'D': result = 'd'; break;
		case 'p': result = 'p'; break;
		case 'P': result = 'p'; break;
		case 't': result = 't'; break;
		case 'T': result = 't'; break;
		case 'q': result = 'q'; break;
		case 'Q': result = 'q'; break;
		default:
			result = '@';
			GotoXY(38, 24);
			cout << "无效的选择,请重新输入。\n";
			GotoXY(38, 26);
			system("pause");
	}
	getchar();
	system("cls");
	return result;
}

void Initialization(HuffmanTree &HT,int &n)
{
	cout << "请输入树叶结点的个数:" << endl;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cout << "请输入第" << i + 1 << "个字符及权值:";
		if (i == 0) cin >> weight[i];
		else
			cin >>ch[i]>> weight[i];
	}
	ch[0] = ' ';
	InitHuffmanTree(HT, n);
	Create(HT, n, ch, weight);
	Display(HT);
	PutinHT(HT);
	initflag = true;
}

void Encoding(HuffmanTree &HT,int n)
{
	if (!HT.flag)
		PutoutHT(HT, "hfmTree.txt", n);
	HuffmanCoder HC;
	InitHuffmanCoder(HC, n);
	CreateBook(HC, HT);
	cout << endl << "请选择你想要进行的操作:" << endl << "1.默认编码ToBeTran文件" <<endl<< "2.选择文件进行编码" << endl << "3.输入字符进行编码"<<endl;
	char c = getchar();
	char ch[256];
	string s;
	string filename;
	if (c == '1')
	{
		ifstream infile("ToBeTran.txt", ios::in);
		if (!infile)
		{
			cerr << "Error opening file: " << filename << endl;
			return;
		}

		getline(infile, s);
		cout << "从文件ToBeTran中读取的待编码的字符串为:" << s << endl << endl;

		//将大写字母转换为小写字母,进行下一步编码
		for (char& c : s) {
			c = tolower(c);
		}
		// 使用strcpy函数将string复制到char[]数组中
		strcpy_s(ch, sizeof(ch), s.c_str());
		cout << "编码结果:" << endl;
		Coder(HC, ch, "CodeFile");
		cout << "编码的结果同时放入数据文件CodeFile中" << endl << endl;
	}
	else if (c == '2') {
		cout << endl << "请输入你想要进行译码的文件名:";
		getchar();
		cin >> filename;
		ifstream infile(filename, ios::in);
		if (!infile)
		{
			cerr << "Error opening file: " << filename << endl;
			system("pause");
			getchar();
			return;
		}

		getline(infile, s);
		cout << "从文件" << filename << "中读取的待编码的字符串为:" << s << endl << endl;

		for (char& c : s) {
			c = tolower(c);
		}
		strcpy_s(ch, sizeof(ch), s.c_str());
		cout << "编码结果:" << endl;
		string putfilename = filename + "_Encoder.txt";
		Coder(HC, ch, putfilename);
		cout << "编码的结果同时放入数据文件" << putfilename << "中" << endl << endl;
	}
	else {
		cout << "请输入待编码的字符:";
		getchar();
		getline(cin, s);
		cout <<"\n\n输入的待编码的字符串为:" << s << endl << endl;
		for (char& c : s) {
			c = tolower(c);
		}
		strcpy_s(ch, sizeof(ch), s.c_str());
		cout << "编码结果:" << endl;
		string putfilename = s + "_Encoder.txt";
		Coder(HC, ch, putfilename);
		cout << "\n编码的结果同时放入数据文件" << putfilename << "中" << endl << endl;
	}
	getchar();
	system("pause");
}

void Decoding(HuffmanTree& HT, int n)
{
	if (!HT.flag)
		PutoutHT(HT, "hfmTree.txt", n);
	cout << endl << "请选择你想要进行的操作:" << endl << "1.默认译码CodeFile文件" << endl << "2.选择文件进行译码" << endl << "3.输入字符进行译码" << endl;
	char c = getchar();
	char ch[256];
	if (c == '1')
	{
		ifstream infile("CodeFile.txt", ios::in);
		if (!infile)
		{
			cerr << "Error opening file: " << "CodeFile.txt" << endl;
			return;
		}
		int j = 0;
		while (infile.get(ch[j]))
			j++;
		ch[j] = '\0';
		Decoder(HT,ch, "TextFile.txt");
	}
	else if (c == '2')
	{
		cout << endl << "请输入你想要进行译码的文件名:";
		string filename;
		cin >> filename;
		ifstream infile(filename, ios::in);
		if (!infile)
		{
			cerr << "Error opening file: " << filename << endl;
			return;
		}
		int j = 0;
		while (infile.get(ch[j]))
			j++;
		ch[j] = '\0';
		string putfilename = filename + "_Decoder.txt";
		Decoder(HT, ch, putfilename);
	}
	else if (c == '3')
	{
		cout << endl << "请输入你想要进行译码的字符:";
		cin >> ch;
		string putfilename = string(ch) + "_Decoder.txt";
		Decoder(HT, ch, putfilename);
	}
	else {
		cout << "输入错误";
	}
	getchar();
	system("pause");
}

void Print()
{
	cout << "请选择你想要进行的操作:" << endl << "1.打印默认的代码文件CodeFile" << endl << "2.选择需要打印的代码文件"<<endl;
	char ch;
	ch = getchar();
	string filename;
	if (ch == '1')
	{
		filename = "CodeFile.txt";
	}
	else if (ch == '2')
	{
		cout << endl << "请输入你想要进行译码的文件名:";
		cin >> filename;
	}
	ifstream inputFile(filename);

	// 检查文件是否成功打开
	if (!inputFile.is_open()) {
		std::cerr << "无法打开"<<filename<<" 文件!" << endl;
		return;
	}

	// 打开 CodePrin 文件进行写入
	string putfilename = filename + "CodePrin.txt";
	ofstream outputFile(putfilename);

	// 检查文件是否成功创建
	if (!outputFile.is_open()) {
		std::cerr << "无法创建"<<putfilename<<" 文件!" << endl;
		return ; // 退出程序
	}

	string line;
	while (getline(inputFile, line)) {
		// 在终端上以紧凑格式显示每行50个代码字符
		for (size_t i = 0; i < line.length(); i += 50) {
			cout << line.substr(i, 50) << endl;
		}

		// 将紧凑格式的编码写入 CodePrin 文件
		for (size_t i = 0; i < line.length(); i += 50) {
			outputFile << line.substr(i, 50) << "\n";
		}
	}

	// 关闭文件
	inputFile.close();
	outputFile.close();
	getchar();
	system("pause");
}

void printHuffmanTree(const HuffmanTree& huffmanTree, int root, int level = 0) {
	if (root != -1) {
		// 打印右子树
		printHuffmanTree(huffmanTree, huffmanTree.ht[root].rchild, level + 1);

		// 打印当前节点
		for (int i = 0; i < level; i++) {
			cout << "--";
		}
		if(huffmanTree.ht[root].rchild==-1&&huffmanTree.ht[root].lchild==-1)
			cout << huffmanTree.ht[root].ch << "(" <<huffmanTree.ht[root].weight << ")" << endl;
		else 
			cout <<  "("  << huffmanTree.ht[root].weight << ")" << endl;

		// 打印左子树
		printHuffmanTree(huffmanTree, huffmanTree.ht[root].lchild, level + 1);
	}
}

// 递归方式写入哈夫曼树到文件
void writeHuffmanTreeToFile(const HuffmanTree& huffmanTree, int root, ofstream& outFile,int level=0) {
	if (root != -1) {
		// 写入右子树
		writeHuffmanTreeToFile(huffmanTree, huffmanTree.ht[root].rchild, outFile,level+1);

		for (int i = 0; i < level; i++) {
			outFile << "--";
		}

		// 写入当前节点
		if (huffmanTree.ht[root].rchild == -1 && huffmanTree.ht[root].lchild == -1)
			outFile << huffmanTree.ht[root].ch << "("  << huffmanTree.ht[root].weight << ")" << endl;
		else
			outFile << "("  << huffmanTree.ht[root].weight << ")" << endl;

		// 写入左子树
		writeHuffmanTreeToFile(huffmanTree, huffmanTree.ht[root].lchild, outFile,level+1);
	}
}


void Tree_printing(HuffmanTree& HT,int n)
{
	if (!HT.flag)
		PutoutHT(HT, "hfmTree.txt", n);
	
	cout << "Huffman Tree:" << endl;
	printHuffmanTree(HT, 2*(n-1));

	// 写入文件
	ofstream outFile("TreePrint.txt");
	if (outFile.is_open()) {
		outFile << "Huffman Tree:" << endl;
		writeHuffmanTreeToFile(HT, 2 * (n - 1), outFile);
		outFile.close();
		cout << "Huffman Tree has been written to TreePrint.txt" << endl;
	}
	else {
		cerr << "Unable to open the file." << endl;
	}
	system("pause");
}

int main()
{
	HuffmanTree HT;
	int end = 1;
	int n;
	//int n= Getn("hfmTree.txt");//已正确读取n
	char result='q';
	while (end) {
		result = menu();
		switch (result)
		{
		case 'i':
			Initialization(HT, n);
			break;
		case 'e':
			if(!initflag) 
				n = Getn("hfmTree.txt");
			Encoding(HT, n);
			break;
		case 'd':
			if (!initflag)
				n = Getn("hfmTree.txt");
			Decoding(HT, n);
			break;
		case 'p':
			if (!initflag)
				n = Getn("hfmTree.txt");
			Print();
			break;
		case 't':
			if (!initflag)
				n = Getn("hfmTree.txt");
			Tree_printing(HT,n);
			break;
		case 'q':
			cout << "正在退出系统......";
			end = 0;
			break;
		default:
			
			break;
		}
		
	}
}

 4. 调试分析

1. 建立哈夫曼树的第i个结点需要在前i-1个结点中挑选出两棵无双亲结点而且根结点权值最小的子树。筛选过程采用简单选择,时间复杂度为O(n),这样的选择需要重复n-1次,所以建立哈夫曼树的时间复杂度为O(n*n)

2. 对每个字符的编码,是从树叶结点出发自下而上搜索至根结点的过程,这一搜索过程的时间复杂度为O(lg n),对有n个树叶的哈夫曼树而言,建立编码表的时间复杂度为O(n*lg n)

3. 编码的过程是对所有需要编码的每一个字符到编码表中查找,这一查找过程的时间复杂度为O(n),若需要编码的字符有m个,则编码过程的时间复杂度为O(n*m)

4. 译码的过程是对二进制电文从根节点出发做自上而下搜搜,当搜搜到树叶结点时则确定了一段二进制电文对应的一个字符,这一搜索过程的时间复杂度是O(lg n),若二进制电文中可译出的字符数为m,则译码的过程的时间复杂度为O(m*lg n)

5. 用户手册

1、本程序的执行文件为:哈夫曼编码.exe

2、进入演示程序后,将显示如下的界面,根据提示进行选择想进行的操作

6. 测试结果

下面是各个功能的实现情况

1. 输入i或I,进行初始化

输入树的叶子结点个数,再依次输入字符以及权值

 

建立哈夫曼树,并输出哈夫曼树的静态链表

存于文件“hfmTree”中

2. 输入e或E,进行编码

显示根据在内存中的或者从文件“hfmTree.txt”中读入的哈夫曼树建立的各个字符的编码

用户进行选择进行编码的内容

 

输入1选择默认文档“ToBeTran.txt”

编码结果存入文件“CodeFile”中 

输入2选择文件进行编码

编码结果存入文件中

 输入3在终端输入内容进行编码

编码结果存入文件

3. 输入d或D,进行译码

进行选择需要译码的内容

输入1译码默认文档“CodeFile”

译码结果存入文件“TestFile”

输入2选择文件进行译码

译码结果存入文件

输入3在终端输入内容进行译码

结果存入文件

4. 输入p或P,进行印代码文件 

进行选择需要打印的代码文件

输入1打印默认的代码文件“CodeFile”

输入2选择文件进行打印代码文件

5. 输入t或T,进行印哈夫曼树

存入文件

6.输入q或Q,退出系统

7. 增加了容错处理

PS:详细的运行结果请打开哈夫曼编码.exe文件

7. 附录

源程序文件名清单:main.cpp,哈夫曼编码.exe, Haffman.h

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/463326.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RIPGeo参文33、37(最大化原始图与摄动图之间的一致性):保证不相关信息的消除

RIPGeo中有: 训练目标为: 由于需要准确的地理定位预测,损失鼓励图表示学习来保持IP地理定位的基本信号。同时,和通过最大化原始图与摄动图[33]、[37]之间的一致性,保证了不相关信息的消除。考虑到模型在训练早期的不稳定性,我们不直接同时优化多个训练目标。相反,我们采…

物联网竞赛板CubMx全部功能简洁配置汇总

目录 前言&#xff1a;1、按键&LED灯配置&#xff1a;2、OLED配置&#xff1a;3、继电器配置&#xff1a;4、LORA模块配置&#xff1a;5、矩阵模块&#xff1a;6、串口模块&#xff1a;7、RTC配置&#xff1a;8、ADC模块配置&#xff1a;9、温度传感器模块&#xff1a;后续…

3.Windows下安装MongoDB和Compass教程

Windows下安装MongoDB 总体体验下来&#xff0c;&#xff0c;要比MySQL的安装简单了许多&#xff0c;没有过多的配置&#xff0c;直接就上手了&#xff01; 1、下载 进入官方的下载页面https://www.mongodb.com/try/download/community&#xff0c;如下选择&#xff0c;我选…

【热门话题】前端框架发展史

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 前端开发的历史演变引言第一章&#xff1a;起源与基础建设 - HTML与CSS时代1.1 …

python 爬取人民新闻

基础信息获取&#xff1a; 要闻url&#xff1a;https://www.gov.cn/yaowen/liebiao/home.htm 下一页的url&#xff1a;https://www.gov.cn/yaowen/liebiao/home_1.htm 基础代码&#xff1a; import re import openpyxl import requests from lxml import etree import osdef …

MySQL 篇- Java 连接 MySQL 数据库并实现数据交互

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 JDBC 概述 2.0 实现 Java 连接 MySQL 数据库并实现数据交互的完整过程 2.1 安装数据库驱动包 2.2 创建数据源对象 2.3 获取数据库连接对象 2.4 创建 SQL 语句 2.…

基于Java+SpringMvc+vue+element实现驾校管理系统详细设计

基于JavaSpringMvcvueelement实现驾校管理系统详细设计 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末…

SQLiteC/C++接口详细介绍之sqlite3类(十二)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;十一&#xff09; 下一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;十三&#xff09; ​37.sqlite3_load_extension 用于在SQLit…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Web)下篇

onRequestSelected onRequestSelected(callback: () > void) 当Web组件获得焦点时触发该回调。 示例&#xff1a; // xxx.ets import web_webview from ohos.web.webviewEntry Component struct WebComponent {controller: web_webview.WebviewController new web_webv…

如果要做优化,CSS提高性能的方法有哪些?

文章目录 一、前言二、实现方式内联首屏关键CSS异步加载CSS资源压缩合理使用选择器减少使用昂贵的属性不要使用import其他 三、总结参考文献 一、前言 每一个网页都离不开css&#xff0c;但是很多人又认为&#xff0c;css主要是用来完成页面布局的&#xff0c;像一些细节或者优…

苹果Vision Pro官方应用商店(网页版)正式上线

该网站为用户提供了丰富多样的应用资源,包括娱乐、教育、健康、购物、工具等各种类型的应用和游戏。 1、Apps & Games Arcade:提供各种应用和游戏,包括最新推出的、热门的以及专门为Apple Vision Pro设计的应用和游戏。 2、What’s New:展示最新推出的应用和游戏,让…

计算机网络----计算机网络的基础

目录 一.计算机网络的相关概念 二.计算机网络的功能 三.计算机网络的发展 四.计算机网络的组成 五.计算机网络的分类 六.计算机的性能指标 1.速率 2.带宽 3.吞吐量 4.时延 5.时延带宽积 6.往返时延RTT 7.利用率 七.计算机的分层结构 八.ISO/OSI参考模型 九.OSI…

Text-to-SQL 工具Vanna + MySQL本地部署 | 数据库对话机器人

今天我们来重点研究与实测一个开源的Text2SQL优化框架 – Vanna 1. Vanna 简介【Text-to-SQL 工具】 Vanna 是一个基于 MIT 许可的开源 Python RAG&#xff08;检索增强生成&#xff09;框架&#xff0c;用于 SQL 生成和相关功能。它允许用户在数据上训练一个 RAG “模型”&a…

前端React篇之React的生命周期有哪些?

目录 React的生命周期有哪些&#xff1f;挂载阶段&#xff08;Mounting&#xff09;更新阶段&#xff08;Updating&#xff09;卸载阶段&#xff08;Unmounting&#xff09;错误处理阶段&#xff08;Error Handling&#xff09; React常见的生命周期React主要生命周期 React的生…

(附数据集)基于lora参数微调Qwen1.8chat模型的实战教程

基于lora微调Qwen1.8chat的实战教程 日期&#xff1a;2024-3-16作者&#xff1a;小知运行环境&#xff1a;jupyterLab描述&#xff1a;基于lora参数微调Qwen1.8chat模型。 样例数据集 - qwen_chat.json&#xff08;小份数据&#xff09; - chat.json&#xff08;中份数据&…

怎么判断发票扫描OCR软件好用不好用?

发票扫描OCR&#xff08;Optical Character Recognition&#xff09;是一种将纸质发票上的文字、数字等信息转化为可编辑的文本格式的技术。在现代企业中&#xff0c;随着数字化转型的推进&#xff0c;发票扫描OCR技术变得越来越重要。然而&#xff0c;面对市场上众多的发票扫描…

如何通过人才测评系统来寻找个人的潜能

潜力这个词&#xff0c;有的时候真是虚无缥缈&#xff0c;人们总说人的潜力是无限&#xff0c;又总说人的潜力是有限的&#xff0c;想一想两句话也都有道理&#xff0c;人的潜能怎么可能无限大&#xff1f;但在某些时候&#xff0c;你也许可以做的更好&#xff0c;但是对于这个…

C#,动态规划问题中基于单词搜索树(Trie Tree)的单词断句分词( Word Breaker)算法与源代码

1 分词 分词是自然语言处理的基础,分词准确度直接决定了后面的词性标注、句法分析、词向量以及文本分析的质量。英文语句使用空格将单词进行分隔,除了某些特定词,如how many,New York等外,大部分情况下不需要考虑分词问题。但有些情况下,没有空格,则需要好的分词算法。…

【ESP32接入国产大模型之MiniMax】

1. MiniMax 讲解视频&#xff1a; ESP32接入语言大模型之MiniMax MM智能助理是一款由MiniMax自研的&#xff0c;没有调用其他产品的接口的大型语言模型。MiniMax是一家中国科技公司&#xff0c;一直致力于进行大模型相关的研究。 随着人工智能技术的不断发展&#xff0c;自然语…

前端Vue与uni-app中的九宫格、十二宫格和十五宫格菜单组件实现

在前端 Vue 开发中&#xff0c;我们经常会遇到需要开发九宫格、十二宫格和十五宫格菜单按钮的需求。这些菜单按钮通常用于展示不同的内容或功能&#xff0c;提供给用户快速访问和选择。 一、引言 在前端开发中&#xff0c;九宫格、十二宫格和十五宫格菜单按钮是一种常见的布局…