利用最小堆创建Huffman树代码(C++)

4 篇文章 0 订阅
1 篇文章 0 订阅

第一步,创建“堆”这个数据结构

#pragma once
#include<assert.h>
template <typename E, typename Comp>
class heap
{
private:
	E* Heap;		//Pointer to the heap array
	int maxsize;	//Maximum size of the heap
	int n;			//Number of elements now in the heap
		//Helper function to put element in its correct place,and that moves the father node down
	void siftdown(int pos);
public:
	heap(E* h, int num, int max);
	int size()const;
	bool isLeaf(int pos)const;
	int leftchild(int pos)const;
	int rightchild(int pos)const;
	int parent(int pos)const;
	void buildHeap();
	void insert(const E& it);
	E removefirst();
	E remove(int pos);
};
//Swap two elements in the container
template<typename E>
void swap(E* array, int pos1, int pos2) {
	E temp = array[pos1];
	array[pos1] = array[pos2];
	array[pos2] = temp;
}

//Heap class
// E is the element in heap
//Comp is a class used to compare two elements
//Helper function to put element in its correct place,and that moves the father node down
template <typename E, typename Comp>
void heap<E, Comp>::siftdown(int pos) {
	while (!isLeaf(pos)) {//Stop if pos is a leaf
		int j = leftchild(pos);
		int rc = rightchild(pos);
		if ((rc < n) && Comp::prior(Heap[rc], Heap[j]))
			j = rc;		//Set j to greater child's value
		if (Comp::prior(Heap[pos], Heap[j]))
			return;	//Done
		swap(Heap, pos, j);
		pos = j;		//Move down
	}
}
template <typename E, typename Comp>
heap<E, Comp>::heap(E* h, int num, int max) {
	Heap = h;
	n = num;
	maxsize = max;
	buildHeap();
}
//Return current heap size
template <typename E, typename Comp>
int heap<E, Comp>::size()const {
	return n;
}
//True if pos is a leaf
template <typename E, typename Comp>
bool heap<E, Comp>::isLeaf(int pos)const {
	return ((pos >= n / 2) && (pos < n));
}
//Return leftchild position
template <typename E, typename Comp>
int heap<E, Comp>::leftchild(int pos)const {
	return 2 * pos + 1;
}
//Return rightchild position
template <typename E, typename Comp>
int heap<E, Comp>::rightchild(int pos)const {
	return 2 * pos + 2;
}
//Return parent position
template <typename E, typename Comp>
int heap<E, Comp>::parent(int pos)const {
	return (pos - 1) / 2;
}
//Heapify contents of Heap
template <typename E, typename Comp>
void heap<E, Comp>::buildHeap() {
	for (int i = n / 2 - 1; i >= 0; --i) {
		siftdown(i);
	}
}
//Insert "it" into the heap
template <typename E, typename Comp>
void heap<E, Comp>::insert(const E& it) {
	assert(n < maxsize);	//Terminate if heap is full
	int curr = n++;
	Heap[curr] = it;		//Start at end of heap
	//Move up until curr's parent > curr
	while ((curr != 0) && (Comp::prior(Heap[curr], Heap[parent(curr)]))) {
		swap(Heap, curr, parent(curr));
		curr = parent(curr);
	}
}

template <typename E, typename Comp>
E heap<E, Comp>::removefirst() {
	assert(n > 0);		//Interrupt if heap is empty
	swap(Heap, 0, --n);		//Swap first with last value.
	if (n != 0)siftdown(0);		//Siftdown new root val
	return Heap[n];			//Return deleted value
}

template <typename E, typename Comp>
E heap<E, Comp>::remove(int pos) {
	assert((pos >= 0) && (pos < n));  //Intertupt if it is in bad position
	if (pos == n - 1)n--;		//Last element,no work to do
	else {
		swap(Heap, pos, --n);		//Swap with last value
		while ((pos != 0) && (Comp::prior(Heap[pos], Heap[parent(pos)]))) {
			swap(Heap, pos, parent(pos));		//Push up large key
			pos = parent(pos);
		}
		if (n != 0)siftdown(pos);		//Push down small key
	}
	return Heap[n];
}

(这里用到了模板,所以函数实现最好也写在.h文件中,否则需要对每个模板分别实现,即要一一实现heap<char,…>,heap<int,…>,原因是当编译器把E换成一种类型,比如char的时候,它会自己创建一个heap<char>(假设这样称呼)的类,如果实现与声明分开了,那么编译器会去.cpp文件里面找heap<char>的实现,发现没有,所以会报错“有无法解析的符号…”,因为你的实现文件(.cpp)里的E并没有变成char)

第二步,Huffman树创建(主文件)

#include"heap.h"
#include<time.h>
#include<iostream>
using namespace std;
//Huffman tree node abstract base class
template<typename E> 
class HuffNode {
public:
	virtual ~HuffNode(){}		//Base destructor
	virtual int weight() = 0;	//Return frequency
	virtual bool isLeaf() = 0;	//Determine type
};

template<typename E>	//Leaf node subclass
class LeafNode :public HuffNode<E> {
private:
	E it;			//Value
	int wgt;		//Weight
public:
	LeafNode(const E& val, int freq) {
		it = val;
		wgt = freq;
	}
	int weight() { return wgt; }
	E val() { return it; }
	bool isLeaf() { return true; }
	~LeafNode(){}
};

template<typename E>		//Internal node subclass
class IntlNode : public HuffNode<E> {
private:
	HuffNode<E>* lc;		//Left child
	HuffNode<E>* rc;		//Right child
	int wgt;				//Subtree weight
public:
	IntlNode(HuffNode<E>* l, HuffNode<E>* r) {
		wgt = l->weight() + r->weight();
		lc = l;
		rc = r;
	}
	int weight() { return wgt; }
	bool isLeaf() { return false; }
	HuffNode<E>* left()const { return lc; }
	void setLeft(HuffNode<E>* b) {
		lc = b;
	}
	HuffNode<E>* right()const { return rc; }
	void setRight(HuffNode<E>* b) {
		rc = b;
	}
	~IntlNode(){}
};

template<typename E>
class HuffTree {
private:
	HuffNode<E>* Root;		//Tree root
public:
	HuffTree(E& val, int freq) {	//Leaf constructor
		Root = new LeafNode<E>(val, freq);
	}
	//Internal node construtor
	HuffTree(HuffTree<E>* l, HuffTree<E>* r) {
		Root = new IntlNode<E>(l->root(), r->root());
	}
	HuffTree() { Root = NULL; }
	~HuffTree(){}
	HuffNode<E>* root() { return Root; }
	int weight() { return Root->weight(); }
	};

template<typename E>
class minTreeComp {
public:
	static bool prior(HuffTree<E>* a, HuffTree<E>* b) {
		return b->weight() >= a->weight();
	}
};


//Build a Huffman tree from a collection of frequencies
template<typename E>
HuffTree<E>* buildHuff(HuffTree<E>** TreeArray, int count) {
	heap<HuffTree<E>*, minTreeComp<E>>* forest =
		new heap<HuffTree<E>*, minTreeComp<E>>(TreeArray, count, count);
	HuffTree<char> *temp1, *temp2, *temp3 = NULL;
	while (forest->size() > 1) {
		temp1 = forest->removefirst();	//Pull first two trees
		temp2 = forest->removefirst();	//off the list
		temp3 = new HuffTree<E>(temp1, temp2);	
		forest->insert(temp3);			//Put the new tree back on list
		//因为temp3使用的构造函数是树的指针(HuffTree<E>*),而不是节点的指针(HuffNode<E>*)
		//所以释放树指针指向的空间,并不会影响节点指针所指向的空间
		//(虽然树里面包含了节点的指针,这个节点指针自身的内存被释放了,但是它指向的内存没有被释放)
		//即释放temp1与temp2不会影响temp3
		delete temp1;		//Must delete the remnants(剩余的)  
		delete temp2;		//of the trees we created
	}
	return temp3;
}

template<typename E>
void traverse(HuffNode<E>* forest) {
	if (forest->isLeaf() == true) {
		cout <<((LeafNode<E>*)forest)->val()<<" : "<<forest->weight() << endl;
	}
	else {
		cout << forest->weight()<<endl;
		traverse(((IntlNode<E>*)forest)->left());
		traverse(((IntlNode<E>*)forest)->right());
	}
}

int main() {
	srand((unsigned int)time(0));
	char ch = 'A';
	HuffTree<char>** forests= new HuffTree<char>*[7];
	//vector<HuffTree<char>*>trees;
	for (int i = 0; i < 7; ++i) {
		ch += 1;
	   forests[i]= new HuffTree<char>(ch,rand() % 50 + 1);
}
	HuffTree<char>* forest = buildHuff(forests, 7);
	traverse(forest->root());
}

运行结果

1
2

Reference

《数据结构与算法分析(C++版)(第三版)》P115,P121

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值