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;
}