C++创建哈夫曼树

哈夫曼树介绍:

哈夫曼树介绍https://zhuanlan.zhihu.com/p/54714101

哈夫曼树是一类带权路径最短的树。构造这种树的算法最早由哈夫曼提出,这种树在信息检索中很有用。如用于通讯及数据传送中构造传输效率最高的二进制编码(哈夫曼编码),用于编程中构造平均执行时间最短的最佳判断过程。 

思路:

用一个Map<序号,子树树根> treeMap,去存储所有的子树。

用一个List<int> arr去存储从小到大排序的数字与子树。

arr中的排序组合有四种:数字与数字、数字与子树、子树与数字、子树与子树。

写这出对应这四种情况的函数,用for循环与执行,知道arr中只有一个元素,这个元素就是我们想要的哈夫曼树。

例如:

  • 3  5  7  8  11  14  23  29
  • 7  8  -8  11  14  23  29
  • -8 11  14  -15  23  29
  • 14  -15  -19  23  29
  • -19  23  29  -29
  •  29  -29  -42
  • -58  -42
  • -100

​​​​​​​

计算某个节点的哈夫曼编码,从根节点想左为0,向右为1。

 

#define _CRT_SECURE_NO_WARNINGS
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

typedef struct binaryTree {
	int node = -1;
	struct binaryTree* lchild = NULL, * rchild = NULL;
}Tree, * TreePointer;

void inputElement();
bool compare(int a, int b);
TreePointer myPopArrEleToTree();
int myPopArr();
TreePointer myPopMap(int iindex);
void createSubTree();
void joinNumToSubTree();
void joinSubTreeToNum();
void joinSubTreeToSubTree();
void xin(TreePointer& T);

vector<int> arr;  //用于存储当前所有元素,永远是按绝对值从小到大排序,正常元素为正数,如果是子树为负数  如队列{2,-3 5 -6 7.8} 
map<int, TreePointer> treeMap;  //用于存放子树

int main(void) {
	inputElement();
	while (arr.size()>2) {  //运行到最后只剩两个元素,执行后会生成最后一个树,这个树就是我们要的答案
		if (arr.size() >= 2 && arr[0] > 0 && arr[1] > 0)
			createSubTree();

		//如果两个元素是,一个子树,一个数字
		if (arr.size() >= 2 && arr[0] < 0 && arr[1]>0)
			joinSubTreeToNum();

		if (arr.size() >= 2 && arr[0] > 0 && arr[1] < 0) 
			joinNumToSubTree();

		if (arr.size() >= 2 && arr[0] < 0 && arr[1] < 0) 
			joinSubTreeToSubTree();
	}
	cout << "result: ";
	for (auto t : treeMap) 
		xin(t.second);
	return 0;
}

//输入元素,输入-1退出
void inputElement() {
	int in;
	while (1) {
		cin >> in;
		if (in == -1) break;
		arr.push_back(in);
	}
	sort(arr.begin(), arr.end(), compare);
}

//比较器
bool compare(int a, int b) {
	return abs(a) < abs(b);
}

//获取最小的值并且获取后删除,给树赋值后返回
TreePointer myPopArrEleToTree() {
	TreePointer T = new Tree;
	T->node = arr[0];
	arr.erase(arr.begin());
	return T;
}

//过去arr的第一个元素,并且删除第一个元素
int myPopArr() {
	int i = arr[0];
	arr.erase(arr.begin());
	return i;
}

//获取treeMap中指定的子树,在treeMap中删除这个子树,并返回这个子树
TreePointer myPopMap(int index) {
	TreePointer T = treeMap[index];
	treeMap.erase(index);
	return T;
}

//添加元素
void addToArr(int i) {
	arr.push_back(i);
	sort(arr.begin(), arr.end(), compare);
}

//挨着的如果是两个数字则创建一个子树,并放到treeMap中
void createSubTree() {
	TreePointer T = new Tree;
	T->lchild = myPopArrEleToTree();
	T->rchild = myPopArrEleToTree();
	treeMap[-(T->lchild->node + T->rchild->node)] = T;
	addToArr(-(T->lchild->node + T->rchild->node));
}

//挨着的如果是一个子树与数字创建一个子树,并放到treeMap中
void joinSubTreeToNum() {
	TreePointer T = new Tree;
	int weight = myPopArr();
	T->lchild = myPopMap(weight);
	T->rchild = myPopArrEleToTree();
	treeMap[-(-weight + T->rchild->node)] = T;
	addToArr(-(-weight + T->rchild->node));
}

//挨着的如果是一个数字与子树创建一个子树,并放到treeMap中
void joinNumToSubTree() {
	TreePointer T = new Tree;
	T->rchild = myPopArrEleToTree();
	int weight = myPopArr();
	T->lchild = myPopMap(weight);
	treeMap[-(-weight + T->rchild->node)] = T;
	addToArr(-(-weight + T->rchild->node));
}

//挨着的如果是一个子树与子树创建一个子树,并放到treeMap中
void joinSubTreeToSubTree() {
	TreePointer T = new Tree;
	int weight1 = myPopArr(), weight2 = myPopArr();
	T->lchild = myPopMap(weight1);
	T->rchild = myPopMap(weight2);
	treeMap[-(-weight1 + (-weight2))] = T;
	addToArr(-(-weight1 + (-weight2)));
}

string str = "";
void xin(TreePointer& T) {
	if (T) {
		if (T->node != -1)
			cout << str << " ";
		str += "0";
		xin(T->lchild);
		str = str.substr(0, str.size() - 1);
		str += "1";
		xin(T->rchild);
		str = str.substr(0, str.size() - 1);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值