数据结构|哈夫曼树的实现
BinaryTree.h
#pragma once
#pragma once
#include
using namespace std;
template
struct BTNode {
BTNode() { lchild = rchild = NULL;
}
BTNode(const T& x){
element = x;
lchild = rchild = NULL;
}
BTNode(const T& x, BTNode* l, BTNode* r) {
element = x;
lchild = l;
rchild = r;
}
T element;
BTNode* lchild, *rchild;
};
template
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& left, BinaryTree& right);
//构造一棵二叉树,根的值为x,以left和right为左右子树
void BreakTree(T& x, BinaryTree& left, BinaryTree& 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* root;
//指向根结点的指针
private:
void Clear(BTNode* &t);
//---------------------(华丽分割线)----------------------
void PreOrder(void (*Visit)(T& x),BTNode*t);
void InOrder(void (*Visit)(T& x), BTNode*t);
void PostOrder(void (*Visit)(T& x), BTNode*t);
//---------------------(华丽分割线)----------------------
//分割线内的函数才是主要实现递归遍历算法的函数
};
template
BinaryTree::~BinaryTree() {
Clear();
};
template
bool BinaryTree::IsEmpty()const {
return (root == NULL) ? true : false;
};
template
void BinaryTree::Clear() {
Clear(root);
};
template
void BinaryTree::Clear(BTNode*&t=root) {
if (p!= NULL) {
Clear(p->lchild);
Clear(p->rchild);
delete p;
}
};
template
bool BinaryTree::Root(T& x)const {
if (root == NULL)return false;
else {
x = root.element;
return true;
}
return false;
};
template
void BinaryTree::MakeTree(const T& x, BinaryTree& left, BinaryTree& right) {
if (root || &left == &right)return;
//若root非空,说明root已是某二叉树树根
root = new BTNode(x,left.root,right.root);
left.root = right.root = NULL;
//left和right已与新树结合,故将其指针设为空
};
template
void BinaryTree::BreakTree(T& x, BinaryTree& left, BinaryTree& 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
void BinaryTree::PreOrder(void(*Visit)(T& x)) {
PreOrder(Visit, root);
};
//先序遍历,真正实现的函数
template
void BinaryTree::PreOrder(void(*Visit)(T& x), BTNode* t) {
if (t) {
Visit(t->element);
PreOrder(Visit, t->lchild);
PreOrder(Visit, t->rchild);
}
};
template
void Visit(T& x) {
cout << x << " ";
};
//中序遍历,面向用户
template
void BinaryTree::InOrder(void(*Visit)(T& x)) {
InOrder(Visit, root);
};
//中序遍历,真正实现的函数
template
void BinaryTree::InOrder(void(*Visit)(T& x),BTNode*t) {
if (t) {
InOrder(Visit, t->lchild);
Visit(t->element);
InOrder(Visit, t->rchild);
}
};
//后序遍历,面向用户
template
void BinaryTree::PostOrder(void(*Visit)(T& x)) {
InOrder(Visit, root);
};
//后序遍历,真正实现的函数
template
void BinaryTree::PostOrder(void(*Visit)(T& x),BTNode*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 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
void PrioQueue::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
void PrioQueue::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
void PrioQueue::Append(const T&x) {
if (IsFull())throw Overflow;
q[n++] = x;
//将新元素插入完全二叉树的最后位置
AdjustUp(n - 1);
//新元素插入位置即为n-1,故用AdjustUp调整0~n-1;
}
template
void PrioQueue::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 HfmTree :public BinaryTree {
public :
HfmTreeCreateHfmTree(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
HfmTree HfmTree::CreateHfmTree(T w[], int n) {
PrioQueue>pq(n);
//pq是一个优先权队列,他的元素是哈夫曼树对象
HfmTreex, 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;
}
推荐阅读
- 【生信技能树】R语言练习题|【生信技能树】R语言练习题 - 中级
- java中如何实现重建二叉树
- 种树郭橐驼传(文言句式+古今异义+词类活用+通假字)
- 白杨树
- 08黑龙江迟淑荣弯柳树网络学院第五期学习赵宗瑞老师主讲的(传统文化与身心健康)教育体系心得体会
- [原创]能见沂山一棵树,胜读十年无用书!
- 涵养字外功
- 2018.07.07《刺杀骑士团长》村上春树
- 二叉树路径节点关键值和等于目标值(LeetCode--112&LeetCode--113)
- 撒哈拉沙漠-三毛