1. 程式人生 > >南郵資料結構實驗二——哈夫曼編碼/譯碼系統

南郵資料結構實驗二——哈夫曼編碼/譯碼系統

實驗目標:
        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; }