【数据结构与算法】综合实验-哈夫曼编码器

代码和报告在:https://github.com/chen37058/Huffman-encoder

信息在通讯线路中是以编码形式进行传输的,在接收端采取一种译码的机制将信息“译”出来。
要求:
(1)读取一篇英文文章,先对文章中以空格分隔的英文单词或符号统计词频;
(2)建立哈夫曼树;给出哈夫曼树的存储结构图;
(3)输出每个单词的哈夫曼编码;
(4)利用哈夫曼树,对模拟输入的报文进行编码,并将结果显示出来。

#include<iostream>
#include<string>
#include<map>
#include<algorithm>
#include<fstream>
#include<sstream>
using namespace std;

typedef string * HuffmanCode;

typedef struct {
    int weight;
    int parent, lchild, rchild;
}HTNode, * HuffmanTree;

void readFile(stringstream& ss) {
    string filePath;
    cin >> filePath;
    ifstream ifs(filePath, ios::in);
    if (!ifs.is_open()) return;
    ss << ifs.rdbuf();
    ifs.close();
}
void Count(stringstream& ss, map<string, int>& map, int choice) {
    map.clear();
    if (choice == 1) {
        string word;
        for (int i = 1; ss >> word; ++i) {
            auto pos = map.find(word);
            if (pos == map.end()) map.insert(make_pair(word, 1));
            else pos->second += 1;
        }
    }
    else {
        char c;
        ss.unsetf(ios::skipws);
        for (int i = 1; ss >> c; ++i) {
            string s(1, c);
            auto pos = map.find(s);
            if (pos == map.end()) map.insert(make_pair(s, 1));
            else pos->second += 1;
        }
    }   
}
void Select(HuffmanTree HT, int end, int& s1, int& s2) {
    int i;
    int minWeight = 100000;
    for (i = 1; i < end; i++) {
        if (HT[i].weight < minWeight && HT[i].parent == 0) {
            minWeight = HT[i].weight;
            s1 = i;
        }
    }
    minWeight = 100000;
    for (i = 1; i < end; i++) {
        if (HT[i].weight < minWeight && HT[i].parent == 0 & i != s1) {
            minWeight = HT[i].weight;
            s2 = i;
        }
    }
}
void CreateHuffmanTree(HuffmanTree& HT, map<string, int> map) {
    int n, m, i, s1, s2;
    n = map.size();
    if (n <= 1) return;
    m = 2 * n - 1;
    HT = new HTNode[m + 1];
    auto it = map.begin();
    for (i = 1; i <= m; ++i) {
        if (it != map.end()) {
            HT[i].weight = it->second;
            ++it;
        }
        HT[i].parent = 0;
        HT[i].lchild = 0;
        HT[i].rchild = 0;
    }
    for (int i = n + 1; i <= m; i++) {
        Select(HT, i, s1, s2);
        HT[s1].parent = i;
        HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight + HT[s2].weight;
    }
}
void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int n) {
    int i, c, f;   
    HC = new string[n + 1];
    for (i = 1; i <= n; ++i) {
        c = i;
        for (f = HT[c].parent; f != 0; c = f, f = HT[c].parent) {
            if (HT[f].lchild == c) HC[i].append("0");           
            else HC[i].append("1");               
        }
        reverse(HC[i].begin(), HC[i].end());
    }
}
void PaperEncode(HuffmanCode HC, map<string, int>& map, stringstream& ss, int choice) {
    char c;
    string str;
    if (choice == 1) {
        while (ss >> str) {
            auto it = map.begin();
            for (int i = 1; it != map.end(); ++i, ++it)
                if (it->first == str) { cout << HC[i]; break; }
            if (it == map.end()) cout << "#";
        }
    }
    else {
        ss.unsetf(ios::skipws);
        while (ss >> c) {
            string str(1, c);
            auto it = map.begin();
            for (int i = 1; it != map.end(); ++i, ++it)
                if (it->first == str) { cout << HC[i]; break;}
            if (it == map.end()) cout << "#";
        }
    }   
} 
void ShowHuffmanTree(HuffmanTree HT, map<string, int> map) {   
    int m = map.size() * 2 - 1; auto it = map.begin(); string str;
    for (int i = 1; i <= m; ++i) {
        cout << i << "\t";        
        if (it != map.end()) {
            if (it->first == "\n") str = "\\n";
            else str = it->first;
            it++;
            cout << str << " \t";
        }
        else cout << " \t";
        cout<< HT[i].weight << "\t" << HT[i].parent << "\t" << HT[i].lchild << "\t" << HT[i].rchild << endl;
    }
}
void ShowHuffmanCode(map<string, int> map, HuffmanCode HC) {
    int i, n = map.size();
    auto it = map.begin();
    string str;    
    for (i = 1; i <= n; i++, it++) {
        if (it->first == "\n") str = "\\n";
        else str = it->first;
        cout << str << " \t" << HC[i] << endl;
    }
}
int main() {
    map<string, int> m;    
    HuffmanTree HT = NULL;
    HuffmanCode HC = NULL;
    int choice;
    while (true) {
        system("cls");
        int num;
        cout << "请选择功能 1.统计词频并创建哈夫曼树 2.进行哈夫曼编码 3.对文章进行编码 4.退出:";
        cin >> num;
        switch (num) {
            case 1: {
                cout << "请输入文件路径:";
                stringstream ss;
                readFile(ss);
                cout << "请选择编码方式 (1.单词 2.字符):";
                cin >> choice;
                Count(ss, m, choice);
                CreateHuffmanTree(HT, m);
                cout << "创建哈夫曼树成功!下面是哈夫曼树的参数输出:" << endl;
                if (choice == 1) cout << "序号\t单词\t词频\t父结点\t左孩子\t右孩子\n";
                else cout << "序号\t字符\t词频\t父结点\t左孩子\t右孩子\n";
                ShowHuffmanTree(HT, m);
                system("pause");
                break;
            }
            case 2: {
                HuffmanCoding(HT, HC, m.size());     
                if (choice == 1) {
                    cout << "哈夫曼编码成功!下面是每个单词编码:" << endl;
                    cout << "单词\t哈夫曼编码" << endl;
                }
                else {
                    cout << "哈夫曼编码成功!下面是每个字符的编码:" << endl;
                    cout << "字符\t哈夫曼编码" << endl;
                }
                ShowHuffmanCode(m, HC);
                system("pause");
                break;
            }
            case 3: {
                stringstream ss2;
                cout << "请输入要编码的文章的文件路径:";
                readFile(ss2);
                cout << "文章编码成功!下面是文章编码结果(在编码表中不存在的用“#”代替):" << endl;
                PaperEncode(HC, m, ss2, choice);
                system("pause");
                break;
            }
            case 4: return 0;
        }
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值