南郵資料結構實驗二——哈夫曼編碼/譯碼系統
阿新 • • 發佈:2019-01-05
實驗目標:
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;
}