哈夫曼树的C++实现

考古一下,大一用C++写的哈夫曼树,环境VS2017。
main函数里改一下文件路径即可运行,输入的是txt文件,文件里最好不要有中文,不然会显示一堆问号;输出哈弗曼编码之后的结果。
但是代码还是有很多问题,当年为了图方便把一些变量和对象搞成了全局的,直接在函数里操作了,这样显然还是不够,还可以改进。

#include
#include
#include
using namespace std;

template<typename E> void swap(E *temp1, E *temp2)        //用于排序的交换函数
{
	E temp = *temp1;
	*temp1 = *temp2;
	*temp2 = temp;
}

int SIZE;                                               //总结点个数
int sum;                                                //总权值

template<typename E> class HaffmanNode  {                //Haffman结点类
public:
	E element;
	int weight;
	HaffmanNode<E>*left;
	HaffmanNode<E>*right;
	bool isLeaf;
	int parent;
	                                                    
	HaffmanNode() {}                              //构造函数
	HaffmanNode(const E&Elem, int wgt,HaffmanNode<E>*le = NULL, HaffmanNode<E>*ri = NULL) {
		element = Elem;
		weight = wgt;
		left = le;
		right = ri;
		isLeaf = true;
	}

	HaffmanNode(int wgt, HaffmanNode<E>*le, HaffmanNode<E>*ri) {
		weight = wgt;
		left = le;
		right = ri;
		isLeaf = false;
	}

	void operator =(HaffmanNode<E> temp) {        //重载=号
		element = temp.element;
		weight = temp.weight;
		left = temp.left;
		right = temp.right;
		isLeaf = temp.isLeaf;
	}

};
int n = 0;                  //仅第一次输出“根结点”,这是一个开关
template<typename E> void preorder(HaffmanNode<E>*root) {    //前序遍历     
	if (root == NULL) { return;}
	if (root->isLeaf) cout << " 叶子结点 元素:" << root->element << " " << "权值:" << root->weight <<"  ";
	if (!root->isLeaf) {
		if (!n) {
			cout << "逐层打印Haffman树:" << endl << endl;
		cout << "根结点:权值" << root->weight << " "; n=1;
		}
		else
		cout << "分支结点:权值" << root->weight << " ";
		cout << "(左结点是";
		if (root->left->isLeaf)
			cout << "叶子结点【" << root->left->element<<","<< root->left->weight << "】 ";
		else
			cout << "分支结点 权值:" << root->left->weight << " ";

		cout << "右结点是";
		if (root->right->isLeaf)
			cout << "叶子结点 【" << root->right->element << "," << root->right->weight << "】) ";
		else
			cout << "分支结点 权值:" << root->right->weight << " ) ";
		cout << endl;
	}
	preorder(root->left);
	preorder(root->right);
}

template<typename E> class NODE {                          //队列结点类
public:
	HaffmanNode<E>*element;
	NODE *next;
	NODE( HaffmanNode<E>* elemval, NODE*nextval = NULL) {   //有初始化元素值结点构造函数
		element = elemval;
		next = nextval;
	}
	NODE(NODE*nextval = NULL) {                            //无初始化元素值结点构造函数
		next = nextval;
	}
};

template <typename E> class Queue :public NODE<E> {           //队列实现
private:
	NODE<E>*front;
	NODE<E>*rear;
	int Size;
public:
	Queue() {
		front = rear = new NODE<E>();
		Size = 0;
	}

	~Queue() {
		while (front->next != NULL) {   
			rear = front;
			delete rear;
		}
		rear = front;
		delete front;
		Size = 0;
	}

	void InQueue( HaffmanNode<E>*it) {                       //入队函数
		rear->next = new NODE<E>(it, NULL);
		rear = rear->next;
		Size++;
	}

	void OutQueue() {                                       //出队函数
		NODE<E>*temp = front->next;
		front->next = temp->next;
		if (temp == rear)
			rear = front;
		delete temp;
		Size--;
	}

	int length() {                                          //长度函数
		return Size;
	}
	HaffmanNode<E>* frontvalue() {                          //队首元素
		return front->next->element;
	}

	HaffmanNode<E>* rearvalue() {                            //队尾元素
		return rear->element;
	}
	NODE<E>* frontnode() {                                  // 队首结点
		return front->next;
	}
	NODE<E>* rearnode() {                                   // 队尾结点
		return rear;
	}

	void display() {                                        //显示队列函数
		if (Size == 0) {
			cout << "空队列!" << endl;
			return;
		}
		NODE<E>*p = front;
		do {
			p = p->next;
			if (p->element->isLeaf)
				cout << "叶子结点 元素:" << p->element->element << " " << "权值:" << p->element->weight << endl;
			else {
				cout << "分支结点:(总权值"<<p->element->weight<<")";
				cout << " 左结点是";
				if (p->element->left->isLeaf) 
					cout << "叶子结点 元素:" << p->element->left->element << " " << "权值:" << p->element->left->weight <<"  ";
				else
					cout << "分支结点 权值:" << p->element->left->weight<<"  ";

				cout << "右结点是";
				if (p->element->right->isLeaf) 
					cout << "叶子结点 元素:" << p->element->right->element << " " << "权值:" << p->element->right->weight << "  ";
				else 
					cout << "分支结点 权值:" << p->element->right->weight<<"  ";
				cout << endl;
			}
		} while (p->next != NULL);
		cout << endl;
	}

	int x;                                                  //统计排序次数的变量
	void sort() {                                           //排序函数
		NODE<E>*p = NULL;
		NODE<E>*q = NULL;
		p = front->next;
		for (int i = 1; i < SIZE; i++) {
			if (p->next == NULL) break;
			q = p->next;
			for (int j = 0; j < SIZE - i; j++) {
				if (q == NULL) break;
				if ((p->element->weight) >(q->element->weight))
					swap(p->element, q->element);
				q = q->next;
			}
			p = p->next;
		}
		p = front->next;                            //重复元素位置交换
		for (int i = 1; i < SIZE; i++) {
			if (p->next == NULL) break;
			q = p->next;
			for (int j = 0; j < SIZE - i; j++) {
				if (q == NULL) break;
				if ((p->element->weight) == (q->element->weight))
					swap(p->element, q->element);
				q = q->next;
			}
			p = p->next;
		}
		x++;
		cout << "第"<<x<<"次:"<<endl;
		display();
	}
};

template<typename E>class Link                              //链表的结点类
{
public:
	E element;
	Link<E>*next;

	Link(const E&elemval, Link<E>* nextval = NULL)
	{
		element = elemval;
		next = nextval;
	}
	Link(Link<E>* nextval = NULL)
	{
		next = nextval;
	}
};


template<typename E>class Linklist :public Link<E>            //链表实现   
{
private:
	Link<E> *head;
	Link<E> *tail;
	Link<E> *curr;
	int count;
public:
	Linklist() {
		curr = tail = head = new Link<E>;
		count = 0;
	}

	~Linklist() {
		while (head != NULL) {
			curr = head;
			head = head->next;
			delete curr;
		}
	}

	void display()
	{
		for (curr = head; curr->next != NULL; curr = curr->next)
			cout << curr->next->element;
		cout << endl;
	}

	void append(const E &it)
	{
		tail = tail->next = new Link<E>(it, NULL);
		count++;
	}
	void LastFront()                     //curr移至最后一个节点前
	{
		curr = head;
		if (curr->next == NULL)
			return;
		while (curr->next != tail)
		{
			curr = curr->next;
		}
	}
	void DeleteLast() {                     //删除尾结点
		if (head->next == NULL) {
			return;
		}
		LastFront();
		Link<E>*temp = tail;
		tail = curr;
		tail->next = NULL;
		delete temp;
		count--;
	}
};

int k = 1;
Linklist<int> Llist;
void Code(HaffmanNode<char>*root) {                     //编码
	if (k) {
		cout << endl<<endl;
		cout << "编码:" << endl;
		k = 0;
	}
	if (root == NULL)return;
	if (root->element != '\0') {
		cout << root->element<<":";
		Llist.display();
		return;
	}
	Llist.append(0);
	Code(root->left);
	Llist.DeleteLast();
	Llist.append(1);
	Code(root->right);
	Llist.DeleteLast();                                    //递归
}

	HaffmanNode<char> *hfm[128];
	Queue<char> Q;

	void InFILE(string s)                               //读文件,建立队列
	{
		string str = "";
		fstream File;
		char c;
		File.open(s, ios::in);

		do {
			File >> c;
			str += c;
		} while (!File.eof());
		int X = str.length();
		str.erase(X - 1, 1);
		cout << "读出文件:" << endl;
		cout << str << endl;
		File.close();
		int x = str.length();
		char *jd = new char[x];                        //结点
		int *qz = new int[x];                          //权值
		for (int i = 1; i < x; i++) { qz[i] = 0; jd[i] = '\0'; }

		jd[0] = str[0]; qz[0] = 1; int size = 1; int k = 0;

		for (int i = 1; i < x; i++) {                             //开始统计
			for (k = 0; k <size; k++) {
				if (jd[k] == str[i]) {
					qz[k]++;
					goto L;
				}
				else
				{
					continue;
				}
			}
			jd[k] = str[i];
			qz[k]++;
			size++;
		L:
			continue;
		}
		cout <<endl<< "统计所有元素及其权值,排序如下:" << endl;
		for (int m = 1; m<size; m++)                        //排序
			for (int n = m; n > 0; n--)
			{
				if (qz[n] < qz[n - 1]) {
					swap(qz[n], qz[n - 1]);
					swap(jd[n], jd[n - 1]);
				}
			}
		for (int i = 0; i < size; i++) {
			sum += qz[i];
			cout << jd[i] << " " << qz[i] << endl;
		}
		cout << endl;
		SIZE = size;
		for (int i = 0; i < SIZE; i++)
		{
			hfm[i] = new HaffmanNode<char>(jd[i], qz[i]);            //封装
			Q.InQueue(hfm[i]);                         //建队列
		}
		cout << "创建队列 :" << endl;
		Q.display();
		cout << endl << "队列创建完成!" << endl;
	}

	void buildTree() {                                   //建立哈夫曼树
		cout << "开始建立Haffman树:" << endl;
		while (Q.rearvalue()->weight < sum) {
			int we = Q.frontvalue()->weight + Q.frontnode()->next->element->weight;
			HaffmanNode<char>*temp1 = Q.frontvalue();
			Q.OutQueue();
			HaffmanNode<char>*temp2 = Q.frontvalue();
			Q.OutQueue();
			HaffmanNode<char>*temp = new HaffmanNode<char>(we, temp1, temp2);
			Q.InQueue(temp);
			Q.sort();
		};
		cout << "Haffman树建立成功!" << endl << endl;
	}

int main() {
	InFILE("d:\\code.txt");                   //数据的统计与预处理
	buildTree();                              //建树
	HaffmanNode<char>*temp = Q.rearvalue();   
	preorder(temp);                              //前序遍历,打印
	Code(temp);                              //编码并输出
	system("pause");
	return 0;
}

测试了一下,没什么问题。
输入:哈夫曼树的C++实现_第1张图片
输出:
哈夫曼树的C++实现_第2张图片

你可能感兴趣的:(C++学习)