c++哈夫曼编码,压缩,解压,译码,以及建立动态哈夫曼树(北理工大作业)

这部分是组长分给我的任务,查了很多资料,下面是代码,恕我愚钝,代码冗长,但结果正确,可供参考

​
//将待压缩信息输入到“myfile.txt”文件中后,就能建立哈夫曼树,进行哈夫曼编码、压缩、解压,译码,动态哈夫曼编码、压缩、解压和动态哈夫曼树建立成功。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>
#include<string>
#include<cstdio>
using namespace std;
void hyasuo();
void hjieguo();
void hjieyasuo();
struct enode
{
	char data;
	enode* parent;
	enode* lenode;
	enode* renode;
	enode* next;
	enode* former;
	int num;//权重
	enode()
	{
		data = '\0';
		num = 0;
		parent = NULL;
		lenode = NULL;
		renode = NULL;
		next = NULL;
		former = NULL;
	}
};
class trees//哈夫曼编码
{
private:
	enode* head;
	int num;
	enode* rear;
public:
	trees()
	{
		num = 0;
		head = new enode;
		rear = new enode;
		head->next = rear;
		rear->former = head;
	}
	void create(int a,int b)
	{
		enode* p = new enode;
		p->data = a+'a';
		p->num = b;
		head->next->former = p;
		p->next = head->next;
		head->next = p;
		p->former = head;
	}
	void encoding()//哈夫曼树
	{
		while (head->next->next != rear)
		{
			find();
		}
	}
	void find()//查找第一小与第二小的节点,合并并删除
	{
			int a = 1000, b = 1000;
			enode* p = new enode, * q=new enode, * w=new enode;
			p = head->next;
			while (p != rear)
			{
				if (p->num < a)
				{
					a = p->num;
					q = p;
				}
				p = p->next;
			}
			p = head->next;
			while (p != rear)
			{
				if (p->num < b && p != q)
				{
					b = p->num;
					w = p;
					
				}
				p = p->next;
			}
			sum(q, w);
			
	}
	void sum(enode* &q, enode* &w)
	{
		enode* e = new enode;
		e->num = q->num + w->num;
		e->next = head->next;
		head->next->former = e;
		e->former = head;
		head->next = e;
		q->parent = e;
		w->parent = e;
		if (q->num < w->num)
		{
			e->lenode = q;
			e->renode = w;
		}
		else
		{
			e->lenode = w;
			e->renode = q;
		}
		
		
		delet(w);
		delet(q);

	}
	void delet(enode*& p)
	{
		if (p != NULL)
		{
			p->former->next = p->next;
			p->next->former = p->former;
		}
	}
	
	enode*& gethead()
	{
		return head;
	}
	void lencoding()//霍夫曼编码部分:这里规定txt文件内容是由26个字符组成,可以根据需要修改一下
	{
		char a = 'a';
		enode* p = new enode;
		int b[30], i=0;
		enode* q = new enode;

		ifstream fp;
		ofstream fo;
		ofstream ff;
		ff.open("哈夫曼编码结果.txt");
		fo.open("writefile.txt");
		if (!fo)
		{
			cout << "faile" << endl;
			exit(1);
		}
		for (a = 'a'; a < 'z'; a++)
		{
			i = 0;
			search(head->next, a, p);//搜索哈夫曼树中是否有该字符
			if (p->data == a)//有该字符,取得该字符编码
			{
				fo << a<<endl;
				//cout << a << ":";
				q = p;
				while (q != head->next)
				{
					if (q->parent->lenode == q)
						b[i] = 0;
					else
						b[i] = 1;
					i++;
					q = q->parent;
				}
				i--;
				for (i; i >= 0; i--)
				{
					fo << b[i];
					

				}
				fo << endl;
			}
		}
		fp.open("myfile.txt", ios::in);
		if (fp.is_open())
		{
			cout << "success" << endl;
		}
		fp >> a;
		while (!fp.eof())
		{
			
			i = 0;
			search(head->next, a, p);//搜索哈夫曼树中是否有该字符
			if (p->data == a)//有该字符,取得该字符编码
			{
				//cout << a << ":";
				q = p;
				while (q != head->next)
				{
					if (q->parent->lenode == q)
						b[i] = 0;
					else
						b[i] = 1;
					i++;
					q = q->parent;
				}
				i--;
				for (i; i >= 0; i--)
				{
					cout << b[i];
					ff << b[i];
					
				}
				//cout << endl;
			}

			if (fp.good())
			{





				fp >> a;
			}
		}
		cout << endl;
		ff.close();
		fp.close();
		fo.close();
	}
	void search(enode*& p, char a, enode*& q)//搜索节点数据;
	{
		if (p->data == a)
		{
			q = p;
			
		}
		if (p->lenode != NULL)
			search(p->lenode, a, q);
		if (p->renode != NULL)
			search(p->renode, a, q);
	}
	void kl(enode*& p)
	{
		cout << endl;
		if (p->data != '\0')
			cout << p->data << endl;
		if (p->renode != NULL)
		{
			kl(p->renode);
		}
		if (p->lenode != NULL)
		{
			kl(p->lenode);
		}
	}

	void pencoding()
	{
		ifstream ff;
		ff.open("哈夫曼编码解压后修正的信息.txt");
		enode* p = new enode;
		p=head->next;
		char c;
		ff >> c;
		while (!ff.eof())
		{
			
			if (c == '0')
			{
				p = p->lenode;

			}
			else
				p = p->renode;
			if (p->lenode == NULL)
			{
				cout << p->data;
				p = head->next;

			}
			ff >> c;
		}
		ff.close();
	}

	
};

struct node//节点定义
{
	char data;
	node* parent;
	node* lnode;
	node* rnode;
	int num;//序号
	int quan;//权重
	node()
	{
		data = '\0';
		parent = NULL;
		lnode = NULL;
		rnode = NULL;
		num = -1;
		quan = 0;
	}
	node(char a, node* b, node* c, node* d,int e,int f)
	{
		data = a;
		parent = new node;
		parent = b;
		lnode = new node;
		lnode = c;
		rnode = new node;
		rnode = d;
		num = f;
		quan = e;
	}
};
class tree//动态哈夫曼编码
{
	node* tr;//根
	int nodenum;//节点的数目&序号
	node* nyt;//动态哈夫曼树的逸出码
public:
	tree()
	{
		nodenum = -1;
		tr = new node;
		nyt = tr;
	}
	
	void creat(char a)//动态哈夫曼树的建立:将输入的字符加入哈夫曼树中,如果树中没有该字符则添加,如果有则对应权重加一;
	{
		
		node* p = new node;
		search(tr,a,p);//搜索哈夫曼树中是否有该字符
		ofstream ff;
		ff.open("动态哈夫曼编码结果.txt",ios::out|ios::app);
		if (p->data==a )//有该字符,对应权重及其所有父节点权重加一
		{

			int b[30];
			int i = 0;
			
			node* f = p;
			while (f != tr)
			{
				if (f->parent->lnode == f)
				{
					b[i] = 0;
				}
				else
				{
					b[i] = 1;
				}
				i++;
				f = f->parent;
			}
			i--;
		
			for (i; i >= 0; i--)
			{
				
				
				cout << b[i];
				ff << b[i];
			}
			node* z = new node;
			node* q = new node;
			q = NULL;
			search(tr, p->quan, q, nyt->num);//按照哈夫曼编码原理,将该字符节点与相同权重下编号最大的节点交换,这是寻找相同权重下的最大编码
			

			
			
			
 
			if (q != NULL&&q->data!=p->data)//找到了最大编号,且不为自己,就将二者交换
			{
				char ch;
				ch = q->data;
				q->data = p->data;
				p->data = ch;
				
			}
//			cout << p<<"  " << q << endl;
				plusone(q);//所有对应的所有父节点权重加一
 
		}

		else//如果哈夫曼树中没有该字符,就把该字符加在原来的nyt节点处
		{
			
			int b[30];
			int i = 0;
			ifstream fp;
			string s;
			string c ;
			c = a;
			fp.open("writefile.txt", ios::in);
			if (nyt == tr)
			{
				cout << "0";
				ff << "0";

			}
			else
			{
				node* f = nyt;
				while (f != tr)
				{
					if (f->parent->lnode == f)
					{
						b[i] = 0;
						
					}
					else
					{
						b[i] = 1;
					}
					i++;
					f = f->parent;
				}
				i--;
				
				for (i; i >= 0; i--)
				{
					
					cout << b[i];
					ff<< b[i];

				}
			}
			while (getline(fp, s))
			{
				
				if (s == c)
				{
					
					getline(fp, s);
					cout << s ;
					ff<< s;
					
				}
			}

			
			--nodenum;
			node* q = new node(a, nyt, NULL, NULL, 1, nodenum);
			--nodenum;
			node* w = new node('\0', nyt, NULL, NULL, 0, nodenum);
			nyt->rnode = q;
			nyt->lnode = w;
			nyt =w;
			plusone(nyt->parent);




		}
		judge(tr);//判断新树是否符合哈夫曼树的条件——父节点权重大于右孩子权重大于左孩子权重,不满足的话就交换左右孩子位置
		
		ff.close();

	}
	void judge(node*& p)
	{
		if (p->lnode != NULL && p->rnode != NULL) 
		{
			if (p->lnode->quan > p->rnode->quan)
			{
				node* q = p->lnode;
				p->lnode = p->rnode;
				p->rnode = q;
			}
			if (p->lnode->lnode != NULL)
			{
				judge(p->lnode);
			}
			if (p->rnode->rnode != NULL)
			{
				judge(p->rnode);
			}
		}
		
	}
	
	void plusone(node*& p)
	{
		node* q = p;
		while (q != NULL)
		{
			q->quan+=1;
			q = q->parent;
			
		}
	}
	void search(node* & p,char a,node*& q)//搜索节点数据;
	{
		if (p->data == a)
			q = p;
		if (p->lnode != NULL)
			 search(p->lnode, a,q);
		if (p->rnode != NULL)
			 search(p->rnode, a,q);
	}
	void search(node*& p, int n,node*& q,int m)//搜索相同权重的节点;
	{
		if (p->quan == n)
		{
			if (p->num > m&&p->data!='\0')
			{
				q = p;
				m = p->num;

			}
		}
		if (p->lnode != NULL)
			search(p->lnode, n, q,m);
		if (p->rnode != NULL)
			search(p->rnode, n, q,m);

	}
	void fread(node* p)//测试是否正确的时候用来读取哈夫曼树各个节点的值,正是代码中可以删去
	{
		cout << endl;
		if(p->data!='\0')
		cout << p->data << ":" << p->quan << endl;
		if (p->rnode != NULL)
		{
			fread(p->rnode);
		}
		if (p->lnode != NULL)
		{
			fread(p->lnode);
		}
		

	}
	
	void pencoding()
	{

	}
	


	node* gettr()
	{
		return tr;
	}

};



int main()
{
	int a[26] = { 0 };
	char c;
	int num=0;
	trees L;
	tree T;
	ifstream fp;
	ofstream ff;
	ff.open("动态哈夫曼编码结果.txt");
	ff.close();
	fp.open("myfile.txt", ios::in);
	
	fp >> c;//动态哈夫曼树建立——每读出一个字符就将该字符添加到哈夫曼树中
	cout << "动态哈夫曼编码:" << endl;
	if (fp.is_open())
	{
		cout << "success" << endl;
	}

	while (!fp.eof())
	{
		if (fp.good())
		{
		
			
			a[c - 'a']++;
			T.creat(c);		
			fp >> c;
			num++;
		}
	}
	fp.close();
	cout << endl;
	for (int i = 0; i < 26; i++)//建立哈夫曼树
	{

		if (a[i] != 0)
		{
			L.create(i, a[i]);

		}
	}
//	T.fread(T.gettr());//测试读出动态哈夫曼树,可删去。

//	L.kl(L.gethead()->next);//测试输出哈夫曼树,可删去。

	

	//哈夫曼编码:
	cout << "哈夫曼编码:" << endl;
	L.encoding();
	L.lencoding();
	
	//哈夫曼编码压缩:
	hyasuo();
	cout << "原文本字符数: " << num << endl;

	//解压缩
	hjieyasuo();


	//哈夫曼译码:
	cout << "原文本内容:" << endl;
	ifstream fd;
	fd.open("myfile.txt");
	fd >> c;

	while (!fd.eof())
	{
		if (fd.good())
		{


			cout << c;
			fd >> c;
		}
	}
	cout << endl;
	cout << "哈夫曼译码结果:" << endl;
	L.pencoding();
	

	//cout << endl;
	//cout << "动态哈夫曼译码结果:" << endl;
	//T.pencoding();


	
	return 0;

}
void hyasuo()
{
	int i = 0,j=0,k;
	char c;
	ifstream fp;
	ofstream ff;
	ff.open("哈夫曼编码压缩后的信息.txt");
	fp.open("哈夫曼编码结果.txt");
	fp >> c;
	i++;
	while (!fp.eof())
	{
		
			
		int l = pow(2, i - 1);
		j +=( c - '0')*l;

		
		if (i == 6)
		{
			char d = (char)j;
			i = 0;
			ff << d;
			k = d;
			j = 0;
		
		}
		fp >> c;
		i++;
	}
	if (i !=0)
	{
		char d = (char)j;
		
		ff << d;
		k = d;
	}
	i--;
	int ch = '0' + i;
	ff << i;

	ff.close();
	fp.close();

	

}
void hjieguo()
{
	ifstream ff;
	ff.open("哈夫曼编码压缩后的信息.txt");
	char c;
	while (!ff.eof())
	{
		ff >> c;
		cout << c;
	}
}
void hjieyasuo()
{
	ofstream ff,ft;
	ifstream fp;
	int j = 0,m;
	fp.open("哈夫曼编码压缩后的信息.txt");
	ff.open("哈夫曼编码解压后的信息.txt");
	ft.open("哈夫曼编码解压后修正的信息.txt");
	char c;
	fp >> c;
	while (!fp.eof())
	{
		int i = (int)c;
		m = c - '0';
		for (int j = 0; j <6; j++)
		{
			ff << i % 2;

			i = i /2;
			
		}
		j++;
		
		
		fp >> c;
	}
	cout << "压缩后文本字符数:" << j << endl;
	ff.close();
	fp.close();
	ifstream g;
	g.open("哈夫曼编码解压后的信息.txt");
	for (int k = 0; k < 6 * (j - 2) +m ; k++)
	{
		char x;
		g >> x;
		ft << x;
	}
	g.close();
	ft.close();
}

​

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值