Haffman编码/译码——数据结构作业(二)

算法:Haffman,DFS
数据结构:queue,Haffman Tree

PS:使用链表建树,但用数组存树操作更方便

// Huffman.cpp : 定义控制台应用程序的入口点。
//

//#include "stdafx.h"

#include "iostream"
#include "stdio.h"
#include "stdlib.h" 
#include "string.h"
#include "string"
#include "queue"
#include "fstream"
const int max_nodenum=100;         //最多字符数 
using namespace std;

struct Node
{
    char ch;
    double weight;
    Node* parent;
    Node* Lchild;
    Node* Rchild;
    Node()
    {
        ch = NULL;
        weight = 0;
        parent = NULL;
        Lchild = NULL;
        Rchild = NULL;
    }
    bool operator < (const Node &a)const   
    {
        return a.weight < weight;
    }
}Hf[max_nodenum];   //Hf[n]用来存储符号信息,和建树无关

struct Info              //打表保存字符编码信息
{
    char ch;
    string code;
}info[max_nodenum];

Node *root;           //huffman树根

void CreateTree()
{
    root = new Node;
    priority_queue <Node> Queue;
    ifstream fin("hfmTree.txt");      //在文件中读取已保存的数据
    int n;
    fin >> n;
    for (int i = 0; i < n; i++)
    {
        fin >> Hf[i].ch >> Hf[i].weight;       
        Queue.push(Hf[i]);
    }
    while (Queue.size() > 1)                     //建树 从下向上
    {
        Node* a = new Node;                      //左子树
        if (Queue.top().ch == NULL)
        {
            *a = Queue.top();
            a->Lchild->parent = a;                  //***被坑了好久
            a->Rchild->parent = a;                  //***
        }
        a->ch = Queue.top().ch;
        a->weight = Queue.top().weight;
        Queue.pop();
        Node *b = new Node;                       //右子树
        if (Queue.top().ch == NULL)
        {
            *b = Queue.top();
            b->Lchild->parent = b;               //***
            b->Rchild->parent = b;               //*** 
        }
        b->ch = Queue.top().ch;
        b->weight = Queue.top().weight;
        Queue.pop();
        Node *ab = new Node;                        //父节点
        ab->weight = a->weight + b->weight;
        ab->Lchild = a;
        ab->Rchild = b;
        a->parent = ab;
        b->parent = ab;
        Queue.push(*ab);
        if (Queue.size() == 1)
            root = ab;              //树根
    }
}

void Initial()
{
    int choose;
    cout << "建树:1.在控制台输入 2.在'hfmTree.txt'文件中读取" << endl;
    cin >> choose;
    if (choose == 1)
    {
        ofstream fclear("hfmTree.txt", std::ofstream::out | std::ofstream::trunc);   //清空原有文件
        cout << "控制台建树:输入字符集大小 n" << endl;
        ofstream fout("hfmTree.txt");            //在文件中输出
        int n;
        cin >> n;
        fout << n << endl;
        cout << "输入:字符 权值" << endl;
        for (int i = 0; i < n; i++)               //输入并输出到文件
        {
            cin >> Hf[i].ch >> Hf[i].weight;
            fout << Hf[i].ch << " " << Hf[i].weight << endl;
        }
        CreateTree();                               //文件中读取数据建树
        cout << "建树成功,并保存到 'hfmTree.txt'中" << endl;
    }
    else if (choose == 2)
    {
        CreateTree();                                //文件中读取数据建树
        //cout << root->weight << " " << root->Lchild->parent->weight;
        cout << "文件中读取数据建树成功" << endl;
    }
    /* 4 a 5 s 10 d 15 f 10 */
}

/*void tv(Node* rot) { cout << rot->weight << " " << rot->ch << endl; if (rot->Lchild == NULL && rot->Rchild == NULL) return; //if(rot->ch!=NULL) if(rot->Lchild!=NULL) tv(rot->Lchild); if(rot->Rchild!=NULL) tv(rot->Rchild); }*/

int info_num = 0;             //字符编码信息数量 
void Traverse(Node *rot)
{
    if (rot->Lchild == NULL && rot->Rchild == NULL)
    {
        info[info_num].ch = rot->ch;
        Node* cur=rot;       
        //cout << cur->weight << " " << cur->parent->parent->weight;
        while (cur->parent!=NULL)
        {
            //cout << cur->weight << " "<<cur->parent->weight;
            if (cur->parent->Lchild == cur)
            {
                info[info_num].code += '0';
            }
            if (cur->parent->Rchild == cur)
            {
                info[info_num].code += '1';
            }
            cur=cur->parent;
        }
        //cout << info[info_num].ch << " " << info[info_num].code << endl;
        int codelen = info[info_num].code.length();
        for (int i = 0; i < codelen/2; i++)            //逆置得正序编码
        {
            int temp = info[info_num].code[i];
            info[info_num].code[i] = info[info_num].code[codelen - i - 1];
            info[info_num].code[codelen - i - 1] = temp;
        }
        info_num++;
        return;
    }
    if (rot->Lchild != NULL)
        Traverse(rot->Lchild);
    if(rot->Rchild!=NULL)
        Traverse(rot->Rchild);
}

void Encoding()
{
    info_num = 0;
    memset(info, 0, sizeof(info));             //初始化
    Traverse(root);                            //遍历打表记录编码映射
    cout << "编码映射如下:" << endl;
    for (int i = 0; i < info_num; i++)
    {
        cout << info[i].ch << " " << info[i].code << endl;
    }
    //tv(root);
    cout << "编码:1.控制台输入数据 2.从文件'ToBeTran.txt'中读取" << endl;
    int choose;
    cin >> choose;
    ofstream fout("CodeFile.txt");                    //编码结果保存文件
    if (choose == 1)
    {
        cout << "输入字符序列:" << endl;
        string str;
        cin >> str;
        //Traverse(root);
        //cout << 111000;
        /* for (int i = 0; i < info_num; i++) { cout << info[i].ch<<" "; cout << info[i].code<<endl; } */
        for (int i = 0; i < str.length(); i++)
        {
            for (int j = 0; j < info_num; j++)
            {
                if (str[i] == info[j].ch)
                {
                    cout << info[j].code;
                    fout << info[j].code;
                }
            }
        }
        cout << endl;
        cout << "以上编码结果已保存到文件'CodeFile.txt'中" << endl;
    }
    else if (choose == 2)
    {
        ifstream fin("ToBeTran.txt");
        string str;
        fin >> str;
        //Traverse(root);
        for (int i = 0; i < str.length(); i++)
        {
            for (int j = 0; j < info_num; j++)
            {
                if (str[i] == info[j].ch)
                {
                    cout << info[j].code;
                    fout << info[j].code;
                }
            }
        }
        cout << endl;
        cout << "以上编码结果已保存到文件'CodeFile.txt'中" << endl;
    }
}

void Decoding()
{
    string str;
    ifstream fin("CodeFile.txt");
    fin >> str;
    ofstream fout("TextFile.txt");
    Node* cur = root;
    int i=0;
    while (i <= str.length())
    {
        if (cur->Lchild == NULL && cur->Rchild == NULL)
        {
            cout << cur->ch;
            fout << cur->ch;
            cur = root;
        }
        if (str[i] == '0')
            cur = cur->Lchild;
        if (str[i] == '1')
            cur = cur->Rchild;
        i++;
    }
    cout << endl;
    cout<< "以上译码结果已保存到文件'TextFile.txt'中" << endl;
}

int main()
{
    cout << "操作菜单:1.建Huffman树 2.编码 3.译码 0.结束"<<endl;
    int n;
    while (cin >> n && n)
    {
        switch (n)
        {
        case 1:Initial();break;
        case 2:Encoding(); break;
        case 3:Decoding();break;
        default:break;
        }
        cout << "操作菜单:1.建Huffman树 2.编码 3.译码 0.结束" << endl;
    }
    return 0;
}

你可能感兴趣的:(Haffman编码/译码——数据结构作业(二))