哈夫曼树的实现


BinaryTree.h

#pragma once
#pragma once  
#include<iostream>  
using namespace std;  
template<class T>  
struct BTNode {  
    BTNode() { lchild = rchild = NULL; }  
    BTNode(const T& x){  
        element = x;  
        lchild = rchild = NULL;  
    }  
    BTNode(const T& x, BTNode<T>* l, BTNode<T>* r) {  
        element = x;  
        lchild = l;  
        rchild = r;  
    }  
    T element;  
    BTNode<T>* lchild, *rchild;  
};  
  
template<class T>  
class BinaryTree {  
public:  
    BinaryTree() { root = NULL; }   
    ~BinaryTree();  
    bool IsEmpty()const;  
    void Clear();//移去所有结点,使其成为空树  
    bool Root(T& x)const;//若二叉树非空,则x为根的值,并返回true,否则返回false  
    void MakeTree(const T& x, BinaryTree<T>& left, BinaryTree<T>& right);//构造一棵二叉树,根的值为x,以left和right为左右子树  
    void BreakTree(T& x, BinaryTree<T>& left, BinaryTree<T>& right);//拆分二叉树为三部分,x为根的值,left和right分别为左右子树  
    //---------------------(华丽分割线)----------------------  
    void PreOrder(void (*Visit)(T& x));//使用函数Visit访问结点,先序遍历二叉树  
    void InOrder(void (*Visit)(T& x));//中序遍历二叉树  
    void PostOrder(void (*Visit)(T& x));//后序遍历二叉树  
    //---------------------(华丽分割线)----------------------  
    //分割线内的函数面向用户,主要提供一个用户与类内递归循环的一个接口  
protected:  
    BTNode<T>* root;//指向根结点的指针  
private:  
    void Clear(BTNode<T>* &t);  
    //---------------------(华丽分割线)----------------------  
    void PreOrder(void (*Visit)(T& x),BTNode<T>*t);  
    void InOrder(void (*Visit)(T& x), BTNode<T>*t);  
    void PostOrder(void (*Visit)(T& x), BTNode<T>*t);  
    //---------------------(华丽分割线)----------------------  
    //分割线内的函数才是主要实现递归遍历算法的函数  
};  
template<class T>  
BinaryTree<T>::~BinaryTree() {  
    Clear();  
};  
template<class T>  
bool BinaryTree<T>::IsEmpty()const {  
    return (root == NULL) ? true : false;  
};  
template<class T>  
void BinaryTree<T>::Clear() {  
    Clear(root);  
};  
template<class T>  
void BinaryTree<T>::Clear(BTNode<T>*&t=root) {  
    if (p!= NULL) {  
        Clear(p->lchild);  
        Clear(p->rchild);  
        delete p;  
    }  
};  
template<class T>  
bool BinaryTree<T>::Root(T& x)const {  
    if (root == NULL)return false;  
    else {  
        x = root.element;  
        return true;  
    }  
    return false;  
};  
template<class T>  
void BinaryTree<T>::MakeTree(const T& x, BinaryTree<T>& left, BinaryTree<T>& right) {  
    if (root || &left == &right)return;//若root非空,说明root已是某二叉树树根  
    root = new BTNode<T>(x,left.root,right.root);  
    left.root = right.root = NULL;//left和right已与新树结合,故将其指针设为空  
};  
template<class T>  
void BinaryTree<T>::BreakTree(T& x, BinaryTree<T>& left, BinaryTree<T>& right) {  
    if (!root || &left == &right || left.root || right.root)return;  
    //如果实参left和right的root非空则说明用户传过来用于获取左右子树的的BTNode指针是某个树的结点  
    x == root->element;  
    left.root = root->lchild; right.root = root->rchild;  
    delete root;  
    root = NULL;  
};  
//先序遍历,面向用户  
template<class T>  
void BinaryTree<T>::PreOrder(void(*Visit)(T& x)) {  
    PreOrder(Visit, root);  
};  
//先序遍历,真正实现的函数  
template<class T>  
void BinaryTree<T>::PreOrder(void(*Visit)(T& x), BTNode<T>* t) {  
    if (t) {  
        Visit(t->element);  
        PreOrder(Visit, t->lchild);  
        PreOrder(Visit, t->rchild);  
    }  
};  
  
  
template<class T>  
void Visit(T& x) {  
    cout << x << " ";  
};  
  
  
//中序遍历,面向用户  
template<class T>  
void BinaryTree<T>::InOrder(void(*Visit)(T& x)) {  
    InOrder(Visit, root);  
};  
//中序遍历,真正实现的函数  
template<class T>  
void BinaryTree<T>::InOrder(void(*Visit)(T& x),BTNode<T>*t) {  
    if (t) {  
        InOrder(Visit, t->lchild);  
        Visit(t->element);  
        InOrder(Visit, t->rchild);  
    }  
};  
  
//后序遍历,面向用户  
template<class T>  
void BinaryTree<T>::PostOrder(void(*Visit)(T& x)) {  
    InOrder(Visit, root);  
};  
//后序遍历,真正实现的函数  
template<class T>  
void BinaryTree<T>::PostOrder(void(*Visit)(T& x),BTNode<T>*t) {  
    if (t) {  
        PostOrder(Visit, t->lchild);  
        PostOrder(Visit, t->rchild);  
        Visit(t->element);  
    }  
};
PrioQueue.h

#pragma once
/*
优先权队列是多个元素的集合,每个元素都有一个优先权。
优先权队列的特点是:每次从队列中取出具有最高优先权的元素
ADT PrioQueue{
Data:
	n个元素的最小堆
Operation:
	Create();//建立一个空队列
	Destroy();//撤销一个队列
	IsEmpty();//空则返回true,非空则false
	IsFull();//满则true,非满则false
	Append(x);//元素值为x的新元素入队
	Serve(x);//将该队列中具有最小优先权的元素值返回给x,并从优先权队列中删除该元素
}
*/
template<class T>
class PrioQueue
{
public:
	PrioQueue(int mSize = 20) {
		maxSize = mSize;
		q = new T[maxSize];
	}
	~PrioQueue() { delete[]q; }
	bool IsEmpty() const{
		return n == 0;
	}
	bool IsFull() {
		return n == maxSize;
	}
	void Append(const T&x);
	void Serve(T& x);
private:
	void AdjustDown(int r, int j);
	void AdjustUp(int j);
	T*q;
	int n, maxSize;
};


template<class T>
void PrioQueue<T>::AdjustDown(int r, int j){
	int child = 2*r + 1;//child定位到r的左子位置
	T temp = q[r];
	while (child <= j) {
		if ((child < j) && (q[child] > q[child + 1]))child++;//找到左右子中最小的那一个
		if (temp <= q[child])break;//如果temp比左右子最小的都小,说明符合向下调整的规则
		q[(child - 1) / 2] == q[child];//将该子值赋给其父结点
		child = 2 * child + 1;//继续向下(跳到该节点的子节点)
	}
	q[(child - 1) / 2] = temp;//temp的位置
}

template<class T>
void PrioQueue<T>::AdjustUp(int j){//j为新插入元素的位置+1
	int i = j; T temp = q[i];
	while (i > 0 && temp < q[(i - 1) / 2]) {
		q[i] = q[(i - 1) / 2];//父子交换
		i = (i - 1) / 2;//跳到该节点的父位置
	}
	q[i] = temp;//i即为temp最后合理的位置
}
//因为插入新元素之前堆中元素都已经满足最小堆的条件
//故只需调整新元素影响到的节点即可
template<class T>
void PrioQueue<T>::Append(const T&x) {
	if (IsFull())throw Overflow;
	q[n++] = x;//将新元素插入完全二叉树的最后位置
	AdjustUp(n - 1);//新元素插入位置即为n-1,故用AdjustUp调整0~n-1;
}
template<class T>
void PrioQueue<T>::Serve(T& x) {
	if (IsEmpty())throw Underflow;
	x = q[0]; //返回具有最低优先权的元素(即堆顶元素)
	q[0] = q[--n];//然后将堆底元素放到堆顶
	AdjustDown(0, n - 1);//向下调整
}

HfmTree.h

#pragma once
#include"BinaryTree.h"
#include"PrioQueue.h"
template<class T>
class HfmTree :public BinaryTree<T> {
public :
	HfmTree<T>CreateHfmTree(T w[], int n);
	operator T()const { return weight; }
	T getW() { return weight; }
	void putW(const T& x) { weight = x; }//设置权重
	setNull() { root = NULL; }
private:
	T weight;
};
template<class T>
HfmTree<T> HfmTree<T>::CreateHfmTree(T w[], int n) {
	PrioQueue<HfmTree<T>>pq(n);//pq是一个优先权队列,他的元素是哈夫曼树对象
	HfmTree<T>x, y, z, zero;
	//----------------------第一个for循环--------------
	for (int i = 0; i < n; i++) {
		z.MakeTree(w[i], x, y);
		z.putW(w[i]);//构造一个数中只有一个结点的哈夫曼树对象
		pq.Append(z);//将哈夫曼树对象放进优先权队列
		z.setNull();//将z置为空数
	}
	//将w数组中的每一个元素当作一个哈夫曼树的权值构造一
	//个只有一个结点的哈夫曼树,pq
	//压进优先权队列pq
	//----------------------第一个for循环--------------
	//----------------------第二个for循环--------------
	for (int i = 1; i < n; i++) {
		pq.Serve(x);//取出最小值
		pq.Serve(y);//取出次最小值
		z.MakeTree(x.getW() + y.getW(), x, y);
				//分别将该次取出的最小值和次最小值当作左、右子
				//构造一个新的哈夫曼树对象
		z.putW(x.getW() + y.getW());
		pq.Append(z);
		z.setNull();
	}
	//对优先权队列pq中的元素(即哈夫曼树对象)进行合并n-1次
	//则最后剩一个完整的即构造完成的哈夫曼树
	//----------------------第二个for循环--------------
	pq.Serve(z);
	return z;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值