数据结构与算法导论(C++)连载(七)--最大堆和哈夫曼编码

本文介绍最大堆和哈夫曼编码的编码实现,包括最大堆的创建、插入、删除最大元素以及哈夫曼编码的构建过程。通过具体代码示例,详细解释了这两种数据结构的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面主要编码实现关于树结构的两种应用-最大堆和哈夫曼编码。

一、最大堆:根结点是整棵树的最大值的完全二叉树,这种结构在排序等功能中应用的比较广,类似的结构有最小堆。

在MaxHeap.h:

#include"iostream"

#define ElementType int
using namespace std;

class MaxHeap
{
public:
	MaxHeap();
	~MaxHeap();
	void CreatMaxHeap(int Maxsize, int MaxData);
	void Insert(ElementType item);
	ElementType DeleteMax();
	bool IsFull();
	bool IsEmpty();
private:
	ElementType * Elements; //存储堆元素
	int Size;
	int Capactiy;
};

在MaxHeap.cpp中:

#include "MaxHeap.h"



MaxHeap::MaxHeap()
{
	Elements = (ElementType *)malloc(sizeof(ElementType));
}


MaxHeap::~MaxHeap()
{
}

void MaxHeap::CreatMaxHeap(int MaxSize, int MaxData) //初始化一个有根结点的最大堆
{
	Size = 1;
	Capactiy = MaxSize;
	Elements[0] = Elements[1] = MaxData;
}

void MaxHeap::Insert(ElementType item) /* 将元素item 插入最大堆H, 其中H->Elements[0]已经定义为哨兵 */
{
	int i;
	if (IsFull()) {
		cout << "error\n";
		return;
	}
	i = ++Size; /* i指向插入后堆中的最后一个元素的位置 */
	for (; Elements[i / 2] < item; i /= 2)
		Elements[i] = Elements[i / 2]; /* 向下过滤结点 */
	Elements[i] = item; /* 将item 插入 */
}

ElementType MaxHeap::DeleteMax()  /* 从最大堆H中取出键值为最大的元素, 并删除一个结点 */
{
	int Parent, Child;
	ElementType MaxItem, temp;
	if (IsEmpty()) {
		cout << "error\n";
		return -1;
	}
	MaxItem = Elements[1]; /* 取出根结点最大值 */
							  /* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */
	temp = Elements[Size--];
	for (Parent = 1; Parent * 2 <= Size; Parent = Child) {
		Child = Parent * 2;
		if ((Child != Size) &&
			(Elements[Child] < Elements[Child + 1]))
			Child++; /* Child指向左右子结点的较大者 */
		if (temp >= Elements[Child]) break;
		else /* 移动temp元素到下一层 */
			Elements[Parent] = Elements[Child];
	}
	Elements[Parent] = temp;
	return MaxItem;
}

bool MaxHeap::IsFull()
{
	if (Size >= Capactiy)
		return 1;
	else
		return 0;
}

bool MaxHeap::IsEmpty()
{
	if (Size == 0)
		return 1;
	else
		return 0;
}

在main.cpp:

#include"MaxHeap.h"

int main()
{
	MaxHeap H;
	H.CreatMaxHeap(10, 58);
	H.Insert(25);
	H.Insert(44);
	cout << H.DeleteMax() << "\n";
	H.Insert(22);
	cout << H.DeleteMax() << "\n";
	system("pause");
	return 0; 
}

二、哈夫曼编码:采用的是哈夫曼数(又称最优二叉树)存储数据

在huffmanTree.h中:

#pragma once
#include"iostream"

using namespace std;

typedef char* HuffmanCode;
typedef struct HTNode *HuffmanTree;
struct HTNode
{
	int weight;
	int parent, leftchild, rightchild;
};

void SelectMin(HuffmanTree HT, int nNode, int s1, int s2);
void HuffmanCoding(HuffmanTree &HT, HuffmanCode HC[], int *w, int nNode);

在HuffmanTree.cpp中:

/*哈夫曼树又称最优二叉树:带权路径长度(WPL)最小的二叉树
1.从原始元素集合T中拿出两个频度最小的元素组成一个二叉树,二叉树的根为这两个节点频度的和。

2.然后从集合T中删除这两个元素,把根元素加入到T集合中,如此反复直集合T为空*/

#include"string.h"
#include"HuffmanTree.h"

//选出weight最小的两个结点,s1保存最小的,s2保存第二小的
void SelectMin(HuffmanTree HT, int nNode,int s1,int s2)
{
	int i, j;
	for (i = 1; i <= nNode; i++)
		if (!HT[i].parent)
		{
			s1 = i;
			break;
		}
	for (j = i + 1; j <= nNode; j++)
		if (!HT[j].parent)
		{
			s2 = j;
			break;
		}
	for (i = 1; i <= nNode; i++)
		if ((HT[i].weight < HT[s1].weight) && (!HT[i].parent) && (s2 != i))
			s1 = i;
	for (j = 1; j <= nNode; j++)
		if ((HT[j].weight < HT[s2].weight) && (!HT[j].parent) && (s1 != j))
			s2 = j;
	// 以上只筛选出最小的两个,这里保证s1的weight比s2的小
	if (HT[s1].weight > HT[s2].weight)
	{
		int tmp = s1;
		s1 = s2;
		s2 = tmp;
	}
}

// w[]存放nNode个字符的权值(均大于0),构造哈夫曼树HT,
// 并求出nNode个字符的哈夫曼编码HC
void HuffmanCoding(HuffmanTree &HT ,HuffmanCode HC[], int *w, int nNode)
{
	int i, j,m,s1=0,s2=0;
	char *hfcode;
	int p;
	int cdlen;
	if (nNode < 1)
		return;
	m = 2 * nNode - 1;   //哈夫曼树的结点数

	/////////////////////////////以下是求Huffman树的初始化/////////////////////////////
	HT = (HTNode*)malloc((m + 1) * sizeof(HTNode));  //0号单元未用
	for (i = 1; i <= nNode; i++)    //初始化
	{
		HT[i].weight = w[i - 1];
		HT[i].parent = 0;
		HT[i].leftchild = 0;
		HT[i].rightchild = 0;
	}
	for (i = nNode + 1; i <= m; i++)
	{
		HT[i].weight = 0;
		HT[i].parent = 0;
		HT[i].leftchild = 0;
		HT[i].rightchild = 0;
	}
	cout << "weight parent lchild rchild:\n";
	for (i = 1; i <= nNode; i++)
		cout << i <<" "<< HT[i].weight << " " << HT[i].parent << " " << HT[i].leftchild << " " << HT[i].rightchild;
	cout << "****************************************************************\n";

	/////////////////////////////以下是求Huffman树的构建/////////////////////////////
	for (i = nNode + 1; i <= m; i++)
	{
		// 建立哈夫曼树
		// 在HT[1..i-1]中选择parent为0且weight最小的两个节点
		// 其序号分别是s1和s2
		SelectMin(HT, i - 1,s1,s2);
		HT[s1].parent = i;
		HT[s2].parent = i;
		cout << "S1 && S2: " << HT[s1].weight << " " << HT[s2].weight << endl;
		HT[i].leftchild = s1;
		HT[i].rightchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
		/*printf("\nselect: s1 = %d s2 = %d\n", s1, s2);*/
		cout << "\nselect: s1 = " << s1 << " s2 = " << s2 << "\n";
		/*printf("结点 weight parent lchild rchild");*/
		cout << "weight parent lchild rchild:\n";
		for (j = 1; j <= i; j++)
			cout << j << " " << HT[j].weight << " " << HT[j].parent << " " << HT[j].leftchild << " " << HT[j].rightchild;
		cout << "****************************************************************\n";
	}
	/////////////////////////////以下是求Huffman树的编码/////////////////////////////
	// 从根出发
	//递归遍历哈夫曼树,求哈夫曼编码
	hfcode = (char *)malloc(nNode * sizeof(char));   //分配求编码的工作空间
	p = m;
	cdlen = 0;
	for (i = 1; i <= m; i++)
		HT[i].weight = 0;   //遍历哈夫曼树时用作结点状态的标志

	while (p)        //退出条件:p = 结点m的parent,即为0
	{
		if (HT[p].weight == 0)   //向左
		{
			HT[p].weight = 1;
			if (HT[p].leftchild != 0)
			{
				p = HT[p].leftchild;
				hfcode[cdlen++] = '0';
			}
			else if (HT[p].rightchild == 0)
			{
				HC[p] = (char *)malloc((cdlen + 1) * sizeof(char));
				hfcode[cdlen] = '\0';   //保证后面的不会被复制
				strcpy_s(HC[p], strlen(hfcode) + 1, hfcode);
			}
		}
		else if (HT[p].weight == 1)   //向右
		{
			HT[p].weight = 2;
			if (HT[p].rightchild != 0)
			{
				p = HT[p].rightchild;
				hfcode[cdlen++] = '1';
			}
		}
		else
		{
			HT[p].weight = 0;
			p = HT[p].parent;
			--cdlen;
		}
	}
}

在main.cpp中:

#include"HuffmanTree.h"

int main()
{

	HuffmanTree HT;   // 哈夫曼树
	HuffmanCode *HC;  // 保存哈夫曼编码
	int *w, nNode, i; // w记录权值
	cout << "Input nNode\n";
	cin >> nNode;
	HC = (HuffmanCode *)malloc(nNode * sizeof(HuffmanCode));
	w = (int *)malloc(nNode * sizeof(int));
	cout << nNode << " of weight";
	for (i = 0; i < nNode; i++)
		cin >> w[i];
	HuffmanCoding(HT, HC, w, nNode);
	cout << "HuffmanTree of nNode\n";
	for (i = 1; i <= nNode; i++)
		cout << i << " " << w[i - 1] << " " << HC[i] << "\n";
	system("pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值