哈夫曼树的生成、编码、译码与输出

//使用数组作为载体,但没有较好地直观呈现的方法,因此放弃了用于初始化存储tree向量的init函数以及相应代码
#include<iostream>
#include <vector>
#include<string>
#include<fstream>

using namespace ::std;

struct node
{
	size_t left, right, parent, freq, p;
	char c;
};

void build(vector<struct node>& nodes);
void sort(vector<struct node>& nodes);
void qsort(vector<struct node>& nodes, size_t low, size_t high);
void swap(vector<struct node>& nodes, size_t low, size_t high);
void encode(vector<struct node>& nodes);
void reverse(string& s);
void decode(vector<struct node>& nodes);
void printTree(vector<struct node>& nodes, int p);
//void init(vector<vector<size_t>>& tree, vector<struct node>& nodes, size_t i, size_t j, size_t p);

string find(vector<struct node>& nodes, char c);

size_t partition(vector<struct node>& nodes, size_t low, size_t high);

int main()
{
	long long n;
	cout << "请输入字符集长度:" << endl;
	cin >> n;//输入字符集长度
	vector<struct node> nodes(n + 1);//初始化字符集
	cout << "请输入字符及其频率:" << endl;
	for (int i = 1; i <= n; i++)
	{
		cin >> nodes[i].c >> nodes[i].freq;
		nodes[i].left = 0;
		nodes[i].right = 0;
		nodes[i].parent = 0;
		nodes[i].p = i;
	}//输入字符集内容

	build(nodes);//根据字符集建立哈夫曼树

	/*
	fstream file1, file2, file3, file4;
	file1.open("TobeTran.txt", ios::in);//file1用于读取原文
	file2.open("CodeFile.txt", ios::out);//file2用于写入编码后的原文
	file3.open("TextFile.txt", ios::out);//写入译文
	file4.open("TreePrint.txt", ios::out);//写入哈夫曼树
	*/

	encode(nodes);//编码
	decode(nodes);//译码
	printTree(nodes, nodes.size() - 1);//输出哈夫曼树

	return 0;
}

void build(vector<struct node>& nodes)
{
	vector<struct node> s(nodes);
	while (s.size() > 2)
	{
		sort(s);//排序,使向量最后两项一直为频率最低的两项
		struct node* tmp = (struct node*)malloc(sizeof(node));

		if (tmp == nullptr)
		{
			exit(-1);
		}

		tmp->parent = 0;
		tmp->left = s[s.size() - 1].p;
		tmp->right = s[s.size() - 2].p;
		tmp->freq = nodes[tmp->left].freq + nodes[tmp->right].freq;
		tmp->p = nodes.size();

		for (int i = 0; i < 2; i++)
		{
			s.pop_back();
		}

		nodes.push_back(*tmp);
		s.push_back(*tmp);

		nodes[tmp->left].parent = nodes.size() - 1;
		nodes[tmp->right].parent = nodes.size() - 1;
	}
}

void sort(vector<struct node>& nodes)
{
	size_t len = nodes.size();
	qsort(nodes, 1, len - 1);//使用快速排序进行排序
}

void qsort(vector<struct node>& nodes, size_t low, size_t high)
{
	size_t pivot;
	if (low < high)
	{
		pivot = partition(nodes, low, high);
		qsort(nodes, low, pivot - 1);
		qsort(nodes, pivot + 1, high);
	}
}

size_t partition(vector<struct node>& nodes, size_t low, size_t high)
{
	size_t pivotkey;
	pivotkey = nodes[low].freq;

	while (low < high)
	{
		while (low < high && nodes[high].freq <= pivotkey)
		{
			high--;
		}

		swap(nodes, low, high);

		while (low < high && nodes[low].freq >= pivotkey)
		{
			low++;
		}

		swap(nodes, low, high);
	}

	return low;
}

void swap(vector<struct node>& nodes, size_t low, size_t high)
{
	struct node tmp;
	tmp = nodes[low];
	nodes[low] = nodes[high];
	nodes[high] = tmp;
}

void encode(vector<struct node>& nodes)
{
	fstream file1, file2;
	file1.open("TobeTran.txt", ios::in);//file1用于读取原文
	file2.open("CodeFile.txt", ios::out);//file2用于写入编码后的原文

	if (!file1.is_open() || !file2.is_open())
	{
		cout << "fail to open!" << endl;
		return;
	}

	char c;
	while ((c = file1.get()) != EOF)
	{
		if (c >= 'A' && c <= 'Z')
		{
			string way = find(nodes, c);
			file2 << way;
		}
		else
		{
			file2 << c;
		}
	}
}

string find(vector<struct node>& nodes, char c)
{
	string s = "";
	size_t p = 0;

	for (size_t i = 0; i < nodes.size(); i++)
	{
		if (nodes[i].c == c)
		{
			p = i;
			break;
		}
	}

	while (p != nodes.size() - 1)
	{
		if (nodes[nodes[p].parent].left == p)
		{
			s.push_back('0');
		}
		else
		{
			s.push_back('1');
		}

		p = nodes[p].parent;
	}

	reverse(s);

	return s;
}

void reverse(string& s)
{
	size_t m = 0, n = s.size() - 1;

	while (m < n)
	{
		char tmp;
		tmp = s[m];
		s[m] = s[n];
		s[n] = tmp;

		m++;
		n--;
	}
}

void decode(vector<struct node>& nodes)
{
	fstream file2, file3;
	file2.open("CodeFile.txt", ios::out || ios :: in);//file2用于写入编码后的原文
	file3.open("TextFile.txt", ios::out);//写入译文

	if (!file2.is_open() || !file3.is_open())
	{
		cout << "fail to open!" << endl;
		return;
	}

	char c;
	size_t p = nodes.size() - 1;
	while ((c = file2.get()) != EOF)
	{
		if (c == '1' || c == '0')
		{
			if (c == '0')
			{
				p = nodes[p].left;
			}
			else if (c == '1')
			{
				p = nodes[p].right;
			}

			if (nodes[p].left == 0 || nodes[p].right == 0)
			{
				file3 << nodes[p].c;
				p = nodes.size() - 1;
			}
		}
		else
		{
			file3 << c;
		}
	}
}

void printTree(vector<struct node>& nodes, int p)
{
	fstream file4;
	file4.open("TreePrint.txt", ios::out);//写入哈夫曼树

	if (nodes[p].left == 0 || nodes[p].right == 0)
	{
		cout << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;
		file4 << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;
		return;
	}

	cout << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;
	file4 << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;

	printTree(nodes, nodes[p].left);
	printTree(nodes, nodes[p].right);

	/*size_t p;
	for (p = 0; p < nodes.size(); p++)
	{
		if (nodes[p].left != 0 || nodes[p].right != 0)
		{
			cout << p << "的位置为:" << nodes[p].p << "  父节点为:" << nodes[p].parent << "  频率为:" << nodes[p].freq << " 无字符" << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
			file4 << p << "的位置为:" << nodes[p].p << "  父节点为:" << nodes[p].parent << "  频率为:" << nodes[p].freq << " 无字符" << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
		} 
		else
		{
			cout << p << "的位置为:" << nodes[p].p << "  父节点为:" << nodes[p].parent << " 频率为:" << nodes[p].freq << " 字符为:" << nodes[p].c << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
			file4 << p << "的位置为:" << nodes[p].p << "  父节点为:" << nodes[p].parent << " 频率为:" << nodes[p].freq << " 字符为:" << nodes[p].c << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
		}
	}

	/*vector<vector<size_t>> tree = {{nodes.size() - 1}};//用于存储哈夫曼树的逻辑结构
	init(tree, nodes, 0, 0, nodes.size() - 1);

	for (int i = 0; i < tree.size(); i++)
	{
		for (int j = 0; j < tree[i].size(); j++)
		{
			cout << nodes[tree[i][j]].p << "处节点的权值为" << nodes[tree[i][j]].freq << " 字符为" << nodes[tree[i][j]].c << " 左孩子为" << nodes[tree[i][j]].left << " 右孩子为" << nodes[tree[i][j]].right << " 父节点为" << nodes[tree[i][j]].parent << ' ';
			file4 << nodes[tree[i][j]].p << "处节点的权值为" << nodes[tree[i][j]].freq << " 字符为" << nodes[tree[i][j]].c << " 左孩子为" << nodes[tree[i][j]].left << " 右孩子为" << nodes[tree[i][j]].right << " 父节点为" << nodes[tree[i][j]].parent << ' ';
		}

		cout << endl;
		file4 << endl;
	}*/
}

/*void init(vector<vector<size_t>>& tree, vector<struct node>& nodes, size_t i, size_t j, size_t p)//初始化tree向量, [i, j]为tree中的位置,p为nods中的位置
{
	if (nodes[p].left == 0)
	{
		return;
	}

	if (i + 1 >= tree.size())//若tree行数不够,则加入新行
	{
		while (i + 1 >= tree.size())
		{
			tree.push_back(vector<size_t>(0));
		}
	}

	if (j + 1 >= tree[i].size())//若行中的位置不够,则加入新位置直到位置足够
	{
		while (j >= tree[i].size())
		{
			tree[i].push_back(0);
		}	
	}

	tree[i + 1].push_back(nodes[p].left);
	tree[i + 1].push_back(nodes[p].right);

	init(tree, nodes, i + 1, j, nodes[p].left);//更新左孩子
	init(tree, nodes, i + 1, j + 1, nodes[p].right);//更新右孩子
}*/

//void print(vector<struct node>& nodes, int i, int j, int p);

代码功底不太好,敬请批评。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值