数据结构 | 构造哈夫曼树

1.向上调整为堆

template<class T>

void Heap<T>::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。

{

int p = size - 1, c = (p - 1) / 2;//`c`表示当前节点的父节点,`p`表示当前节点。

T temp = vec[p];

while (p > 0) //为什么不是c>0

//在`while`循环中,我们判断当前节点是否已经到达根节点,如果是根节点则停止循环。所以条件应该是`p > 0`,而不是`c > 0`。

{

if (vec[c] <= temp)

break;

else

{

vec[p] = vec[c];

p = c;

c = (p - 1) / 2;

}

}

vec[p] = temp; //写在while 里面还是外面目前结点最后会空出来

}


2.向下调整为堆

template<class T>

void Heap<T>::PercolateDown(int h)// 向下调整为堆,如果父亲节点(目前结点)比孩子结点(较小值)大交换

{

int p = h, c = 2 * p + 1;// c为p的左孩子

T t emp = vec[h]; //不定类型 不用写成int

while (c < size) //怎么修改?

{

if (c + 1 < size && vec[c + 1] < vec[c]) //左孩子的下标小于size-1(最后一个叶子结点)&&找到左右孩子的最小值

//c < size表示当前节点有左孩子 ,而c + 1 < size表示当前节点有右孩子。根据堆的性质,选择较小的孩子进行交换。

{

++c;

}

if (temp <= vec[c])

break;

else

{

vec[p] = vec[c];

p = c;

c = 2 * p + 1;

}

}

vec[p] = temp;

}


构造参考:

赫夫曼树_关于huffman树,权值相同-CSDN博客

编码参考:

【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码_数据结构哈夫曼树编码-CSDN博客


cpp 复制代码
#include<iostream>
#include<vector> 
#include<queue>
using namespace std;

template<class T>
struct BTNode
{
	T data;
	BTNode* left, * right;
	BTNode(const T& item = T(), BTNode* lptr = NULL, BTNode* rptr = NULL) :
		data(item), left(lptr), right(rptr) {}
};

void Gotoxy(int x, int y)
{
	static int level = 0, indent = 0;
	if (y == 0)
	{
		indent = 0;
		level = 0;
	}
	if (level != y)
	{
		cout << endl;
		indent = 0;
		level++;
	}
	cout.width(x - indent);
	indent = x;
}

template<class T>
BTNode<T>* GetBTNode(const T& item, BTNode<T>* lp = NULL, BTNode<T>* rp = NULL)
{
	BTNode<T>* p;
	p = new BTNode<T>(item, lp, rp);
	if (p == NULL)
	{
		cout << "error!" << endl;
	}
	return p;
}

struct Location
{
	int xindent, ylevel;
};

template<class T>
void PrintBTree(const BTNode<T>* t, int screenwidth)
{
	if (t == NULL)
	{
		return;
	}
	int level = 0, offset = screenwidth / 2;
	Location floc, cloc;
	queue<const BTNode<T>*> Q;
	queue<Location> LQ;
	floc.xindent = offset;
	floc.ylevel = level;
	Q.push(t);
	LQ.push(floc);
	while (!Q.empty())
	{
		t = Q.front();
		floc = LQ.front();
		Q.pop();
		LQ.pop();
		Gotoxy(floc.xindent, floc.ylevel);
		cout << t->data;
		if (floc.ylevel != level)
		{
			level++;
			offset = offset / 2;
		}
		if (t->left)
		{
			Q.push(t->left);
			cloc.ylevel = floc.ylevel + 1;
			cloc.xindent = floc.xindent - offset / 2;
			LQ.push(cloc);
		}
		if (t->right)
		{
			Q.push(t->right);
			cloc.ylevel = floc.ylevel + 1;
			cloc.xindent = floc.xindent + offset / 2;
			LQ.push(cloc);
		}
	}
	cout << endl;

}

template<class T>
class Heap   //小根堆 根->叶子 小到大
{
	vector<T> vec;
	int size;
	void BuildHeap(void);
	void PercolateUp();
	void PercolateDown(int h);
public:
	Heap(int max = 100) : vec(max), size(0) {}
	Heap(const vector<T>& vt);
	int Size()
	{
		return size;
	}
	void Insert(const T& item);
	void DeleteMin(void);
	void DeleteMin(T& item);
};

template<class T>
void Heap<T>::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。
{

	int p = size - 1, c = (p - 1) / 2;//`c`表示当前节点的父节点,`p`表示当前节点。
	T temp = vec[p];
	while (p > 0) //为什么不是c>0
		

		//在`while`循环中,我们判断当前节点是否已经到达根节点,如果是根节点则停止循环。所以条件应该是`p > 0`,而不是`c > 0`。

		
	{
		if (vec[c] <= temp)
			break;
		else
		{
			vec[p] = vec[c];
			p = c;
			c = (p - 1) / 2;
		}
	}
	vec[p] = temp; //写在while 里面还是外面? 目前结点最后会空出来
}

template<class T>
void Heap<T>::PercolateDown(int h)// 向下调整为堆,如果父亲节点(目前结点)比孩子结点(较小值)大交换
{
	int p = h, c = 2 * p + 1;// c为p的左孩子
	T temp = vec[h];
	while (c < size)  //怎么修改?
	{
		if (c + 1 < size && vec[c + 1] < vec[c]) //左孩子的下标小于size-1(最后一个叶子结点)&&找到左右孩子的最小值
		{
			++c;
		}
		if (temp <= vec[c])
			break;
		else
		{
			vec[p] = vec[c];
			p = c;
			c = 2 * p + 1;
		}
	}
	vec[p] = temp;
}

template<class T>
void Heap<T>::Insert(const T& item)
{
	if (size == vec.size())
	{
		vec.resize(vec.size() *2);
	}
	vec[size] = item;
	size++;
	PercolateUp();
	
}

template<class T>
void Heap<T>::BuildHeap(void) //从最后一个非叶子结点(a)开始,size-1是最后一个叶子结点,a是它的parent
{
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		PercolateDown(i);//为该结点的子树调整成堆
	}
}

template<class T>
void Heap<T>::DeleteMin()
{
	if (size == 0)
	{
		return;
	}
	vec[0] = vec[size - 1];
	size--;
	PercolateDown(0);
}

template<class T>
void Heap<T>::DeleteMin(T& item)
{
	if (size == 0) //删除最小值需要判断堆是否为空
	{
		return;
	}
	item = vec[0];
	vec[0] = vec[size - 1];
	size--;
	PercolateDown(0);
}

template<class T>
Heap<T>::Heap(const vector<T>& vt) : vec(vt.size() + 10), size(vt.size())
{
	for (int i = 0; i < size; i++)
	{
		vec[i] = vt[i];
	}
	BuildHeap();
}

template<class T>
struct HuffmanNode
{
	BTNode<T>* t;
	int operator<(const HuffmanNode& h)//穿入参数是哈夫曼节点 bool类型
	{
		return (t->data < h.t->data);
	}
	int operator<=(const HuffmanNode& h)//穿入参数是哈夫曼节点
	{
		return (t->data <= h.t->data);
	}
};

template<class T>
BTNode<T>* MakeHuffman(T* pa, int n)
{
	BTNode<T>* t, * right, * left;
	HuffmanNode<T> hf;
	Heap<HuffmanNode<T>> HF(n);
	//第一个循环将数组里的元素插入到哈夫曼堆
	for (int i = 0; i < n; i++)
	{
		t = GetBTNode<int>(pa[i]);
		hf.t = t;
		HF.Insert(hf);
	}
	//第二个循环找到最小的两个数,生成根节点后删除
	for (int i = 1; i < n; i++)
	{
		HF.DeleteMin(hf);
		left = hf.t;
		HF.DeleteMin(hf);
		right = hf.t;
		t = GetBTNode(left->data + right->data, left, right);//t的左孩子是left,右孩子是right
		hf.t = t;
		HF.Insert(hf);
	}
	HF.DeleteMin(hf);//是一个对象调用函数
	t = hf.t;
	return t;
};

int main()
{
	int a[] = { 7,5,2,4 };
	BTNode<int>* root;
	root = MakeHuffman(a, 4);
	PrintBTree(root, 40);
	cout << endl;
	return 0;
}
相关推荐
艾莉丝努力练剑22 分钟前
【Linux指令 (二)】不止于入门:探索Linux系统核心与指令的深层逻辑,理解Linux系统理论核心概念与基础指令
linux·服务器·数据结构·c++·centos
C嘎嘎嵌入式开发1 小时前
(10)100天python从入门到拿捏《Python中的数据结构与自定义数据结构》
数据结构·python·算法
Vect__1 小时前
从底层到上层的“外挂”:deque、stack、queue、priority_queue 全面拆解
数据结构·c++
玖釉-2 小时前
三维模型数据结构与存储方式解析
数据结构·算法·图形渲染
努力努力再努力wz2 小时前
【C++进阶系列】:万字详解特殊类以及设计模式
java·linux·运维·开发语言·数据结构·c++·设计模式
青岛少儿编程-王老师12 小时前
CCF编程能力等级认证GESP—C++7级—20250927
数据结构·c++·算法
nanaki5021315 小时前
数据结构(3) ----------- 栈、队列
数据结构
一只小透明啊啊啊啊15 小时前
b树,b+树,红黑树
数据结构·b树·b+树
Mingze031415 小时前
C语言四大排序算法实战
c语言·数据结构·学习·算法·排序算法
程序员东岸15 小时前
学完顺序表后,用 C 语言写了一个通讯录
数据结构·笔记·学习