实验目标:
1、实现二叉树的遍历、计算节点等基本功能
2、编写哈夫曼编码/译码系统
功能流程图:
实验代码:
#include <iostream>
#include <string>
using namespace std;
template <class T>
struct BTNode
{
BTNode()
{
lChild = rChild = parent = NULL;
}
BTNode(const T & x, char & q)
{
element = x;
lChild = rChild = parent = NULL;
ch = q;
}
BTNode(const T & x, char & q, BTNode<T>* l, BTNode<T>* r)
{
element = x;
lChild = l;
rChild = r;
ch = q;
parent = NULL;
}
T element;
BTNode<T> *lChild, *rChild, *parent;
string num; // 储存路径编码,用string不用担心大小问题
char ch; // 储存字符
};
template<class T>
void Visit(T & x)
{
cout << x << " ";
}
template <class T>
class HfmTree;
template<class T>
class BinaryTree
{
public:
BinaryTree();
~BinaryTree();
bool IsEmpty() const;
void Clear() { } // 移去所有结点,成为空二叉树
bool Root(T & x) const; // 若二叉树不空,则x为根的值,并返回true,否则返回false
void MakeTree(const T & x, char c, BinaryTree<T> & left, BinaryTree<T> & right); // 建树
void BreakTree(T & x, BinaryTree<T> & left, BinaryTree<T> & right);
void PreOrder(void (*Visit) (T & x));
void InOrder(void (*Visit) (T & x));
void PostOrder(void (*Visit) (T & x));
int CountNode(); // 计算二叉树的结点个数
void printHfm(); // 输出二叉树的前序和中序遍历
protected:
BTNode<T>* root;
private:
//void Clear(BTNode<T>* t); // 用于析构函数,加了报错orz
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);
int CountNode(BTNode<T> *t); // 计算结点数量
};
template <class T>
BinaryTree<T>::BinaryTree()
{
root = NULL;
}
template <class T>
BinaryTree<T>::~BinaryTree()
{
Clear();
}
template <class T>
bool BinaryTree<T>::IsEmpty() const
{
return root == NULL;
}
//template <class T>
//void BinaryTree<T>::Clear()
//{
//Clear(root);
//root = NULL;
//}
template <class T>
bool BinaryTree<T>::Root(T & x) const
{
if (root) {
x = root->element;
return true;
}
else
return false;
}
//template <class T>
//void BinaryTree<T>::Clear(BTNode<T>* t)
//{
// if (t) {
// Clear(t->lChild);
// Clear(t->rChild);
// delete t;
// t = NULL;
// }
// else
// return;
//}
template <class T>
void BinaryTree<T>::MakeTree(const T & x, char c, BinaryTree<T> & left, BinaryTree<T> & right)
{
if (root || & left == & right) {
cout << "MakeTree fail!" << endl;
return;
}
root = new BTNode<T>(x, c, left.root, right.root);
left.root = right.root = NULL;
}
template <class T>
void BinaryTree<T>::BreakTree(T & x, BinaryTree<T> & left, BinaryTree<T> & right)
{
if (!root || & left == & right || left.root || right.root) {
cout << "BreakTree failed!" << endl;
return;
} else {
x = root->element;
left.root = root->lChild;
right.root = root->rChild;
delete root;
root = NULL;
parent = NULL;
}
}
template <class T>
void BinaryTree<T>::PreOrder(void (*Visit) (T & x))
{
PreOrder(Visit, root);
}
template <class T>
void BinaryTree<T>::InOrder(void (*Visit) (T & x))
{
InOrder(Visit, root);
}
template <class T>
void BinaryTree<T>::PostOrder(void (*Visit) (T & x))
{
PostOrder(Visit, root);
}
template <class T>
int BinaryTree<T>::CountNode()
{
return CountNode(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 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), BTNode<T>* t)
{
if (t) {
PostOrder(Visit, t->lChild);
PostOrder(Visit, t->rChild);
Visit(t->element);
}
}
template <class T>
int BinaryTree<T>::CountNode(BTNode<T> *t)
{
if (t) {
return CountNode(t->lChild) + CountNode(t->rChild) + 1;
}
else
return 0;
}
// 输出哈夫曼树的前序和中序遍历
template <class T>
void BinaryTree<T>::printHfm()
{
cout << "The PreOrder of the HfmTree:" << endl;
PreOrder(Visit);
cout << endl;
cout << "The InOrder of the HfmTree:" << endl;
InOrder(Visit);
cout << endl;
}
enum ResultCode
{
NoMemory,
OutOfBounds,
Underflow,
Overflow,
Duplicate
};
template <class T>
class PriQueue
{
public:
PriQueue(int mSize = 100);
~PriQueue() {delete []q;}
bool IsEmpty() const {return n == 0;}
bool IsFull() const {return n == maxSize;}
void Append(const T & x);
void Serve(T & x);
void print();
private:
void AdjustDown(int r);
void AdjustUp(int j);
T *q;
int n, maxSize;
};
template <class T>
PriQueue<T>::PriQueue(int mSize)
{
maxSize = mSize;
n = 0;
q = new T[maxSize];
}
template <class T>
void PriQueue<T>::Append(const T & x)
{
if (IsFull()) {
cout << "The PriQueue is full!" << endl;
throw Overflow;
}
q[n++] = x;
AdjustUp(n - 1);
}
template <class T>
void PriQueue<T>::Serve(T & x)
{
if (IsEmpty()) {
cout << "The PriQueue is Empty!" << endl;
throw Underflow;
}
x = q[0];
q[0] = q[--n];
AdjustDown(0);
}
template <class T>
void PriQueue<T>::print()
{
for (int i = 0; i < n; i++) {
cout << q[i] << " " << endl;
}
}
template <class T>
void PriQueue<T>::AdjustDown(int r)
{
int Child = 2 * r + 1;
T temp = q[r];
while (Child < n) {
if (Child + 1 < n && q[Child + 1] < q[Child]) {
Child++;
}
if (temp > q[Child]) {
q[r] = q[Child];
r = Child;
Child = 2 * Child + 1;
} else {
break;
}
}
q[r] = temp;
}
template <class T>
void PriQueue<T>::AdjustUp(int j)
{
T temp = q[j];
int i = j;
while (i > 0 && temp < q[(i - 1) / 2]) {
q[i] = q[(i - 1) / 2];
i = (i - 1) / 2;
}
q[i] = temp;
}
template <class T>
class HfmTree:public BinaryTree<T>
{
public:
operator T () const
{
return weight;
}
T getW()
{
return weight;
}
void putW(const T & x)
{
weight = x;
}
void SetNull()
{
root = NULL;
}
void Code(); // 根据输入的字符输出编码
void DeCode() { DeCode(root); cout << endl; } // 根据输入的编码输出字符
void Create_code() { Create_code(root); } // 写入路径编码
void Conn_parent() { Conn_parent(root); } // 令parent指向上级结点
void test() { testprint(root); } // 测试,输出字符对应的编码
private:
void Create_code(BTNode<T>* t);
void DeCode(BTNode<T>* q);
void Conn_parent(BTNode<T>* t);
T weight;
void Code(BTNode<T>* t, char a);
void testprint(BTNode<T>* t);
};
// 打印出所有的结点的权值以及对应的字符
template<class T>
void HfmTree<T>::testprint(BTNode<T>* t)
{
static int u = 0;
if (t)
{
cout << t->num << " " << t->ch << " " << u++ << endl;
testprint(t->lChild);
testprint(t->rChild);
}
}
// 由输入的字符输出相应的编码
template<class T>
void HfmTree<T>::Code()
{
cout << "Please input a string:" << endl;
string s;
cin >> s;
for (int i = 0; i < s.length(); i++) {
Code(root, s[i]);
}
cout << endl;
}
// 由输入的编码输出相应的字符
template<class T>
void HfmTree<T>::DeCode(BTNode<T>* q)
{
cout << "Please input binary-encoded string:" << endl;
string n;
cin >> n;
BTNode<T>* t = q;
int count = n.length();
for (int i = 0; i < count; i++) {
if (n[i] == '0' && t->lChild->ch != '*') {
cout << t->lChild->ch;
t = q;
//cout << "one" << endl; //test
}
else if (n[i] == '1' && t->rChild->ch != '*') {
cout << t->rChild->ch;
t = q;
//cout << "two" << endl;; //test
}
else if (n[i] == '0' && t->lChild != NULL) {
t = t->lChild;
//cout << "three" << endl; //test
}
else if (n[i] == '1' && t->rChild != NULL) {
t = t->rChild;
//cout << "four" << endl; //test
}
else {
cout << "Decode fail!";
return;
}
}
}
// 把空的parent指针指向每个节点的父级指针
template<class T>
void HfmTree<T>::Conn_parent(BTNode<T>* t)
{
if (t) {
if (t->lChild != NULL) {
t->lChild->parent = t;
}
if (t->rChild != NULL) {
t->rChild->parent = t;
}
Conn_parent(t->lChild);
Conn_parent(t->rChild);
}
}
template<class T>
void HfmTree<T>::Code(BTNode<T>* t, char a)
{
if (t) {
if (t->ch == a) {
cout << t->num;
}
Code(t->lChild, a);
Code(t->rChild, a);
}
}
// 用遍历把路径保存在字符串num里
template<class T>
void HfmTree<T>::Create_code(BTNode<T>* t)
{
if (t) {
if (t->parent != NULL) {
if (t == t->parent->lChild) {
t->num = t->parent->num + '0';
}
else if (t == t->parent->rChild) {
t->num = t->parent->num + '1';
}
else
cout << "Creat_code Error!" << endl;
}
Create_code(t->lChild);
Create_code(t->rChild);
}
}
template <class T>
HfmTree<T> CreateHfmTree(T w[], char q[], int n)
{
PriQueue<HfmTree<T>> pQ(n);
HfmTree<T> x, y, z;
for (int i = 0; i < n; i++) {
z.MakeTree(w[i], q[i], x, y);
z.putW(w[i]);
pQ.Append(z);
z.SetNull();
}
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.Serve(z);
return z;
}
int main()
{
cout << "Welcome to Hfm coding / decoding system!" << endl;
cout << "Please input the number of coding characters:" << endl;
int m; // 需要编码的字符数量
cin >> m;
cout << "Please input the character string:" << endl;
char *c = new char[m + 1]; // 储存字符
cin >> c;
cout << "Please input the corresponding weight:" << endl;
int *w = new int[m + 1]; // 储存权值
for (int i = 0; i < m; i++) {
cin >> w[i];
}
HfmTree<int> a = CreateHfmTree(w, c, m);
a.Conn_parent();
a.Create_code();
//a.test(); // 检测编码情况的测试函数
while (1) {
cout << endl;
cout << "Please choose what you want to do:(input number)" << endl;
cout << "1. coding" << endl;
cout << "2. decoding" << endl;
cout << "3. print the HfmTree" << endl;
cout << "4. exit" << endl;
int cho;
cin >> cho;
switch (cho) {
case 1:
a.Code();
break;
case 2:
a.DeCode();
break;
case 3:
a.printHfm();
break;
case 4:
return 0;
}
}
system("pause"); // 在vs上编译运行需要的暂停函数
return 0;
}