南邮数据结构实验二——哈夫曼编码/译码系统

实验目标:
        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;
}
  • 25
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值