构建
效果图

#include<iostream>
#include<algorithm>
#include<string>
#include<fstream>
#include<windows.h>
#include<map>
#include<urlmon.h>
#pragma comment(lib, "urlmon.lib")
using namespace std;
#define N 1010
#define INF 99999
#define PATHIN "F:\\huffumanbase.txt"
#define PATHEN "F:\\encoding.txt"
#define PATHRE "F:\\recoding.txt"
#define Down "https://www.noah-dream.com/usr/uploads/2019/06/2279318315.txt"
struct MyStruct
{
    int weight;
    char code;
    int parent, left, right;
    int flag=0;
};
struct MyStruct1
{
    int index;//当前key的坐标
    string Code;
};
map<char, MyStruct1>::iterator iter;

void createbase()
{
    HRESULT hr = URLDownloadToFile(0, Down, PATHIN, 0, NULL);//不方便输入直接从服务器下载
    if (S_OK != hr)
    {
        cout << "请检查网络是否畅通" << endl;
        exit(0);
    }
    /*cout << "文件默认目录在F盘下,修改请修改PATH路径" << endl;
    cout << "请手动打开F盘下huffumanbase.txt输入" << endl;
    cout << "输入完成后请输入1运行程序" << endl;
    int n;
    while (cin >> n)
    {
        if (n == 1)
            break;
    }*/
}
void createCode(MyStruct huffman[N], map<char, MyStruct1> & key)//创建字母编码
{
    int index, index1;
    for (iter = key.begin(); iter != key.end(); iter++)
    {
        string Code;
        index = iter->second.index;
        index1 = index;
        while (huffman[index].parent != 0)
        {
            index = huffman[index].parent;//找到当前结点的parent结点
            if (index1 == huffman[index].left)//判断当前节点是在parent结点的左边还是右边
            {
                Code += '0';
            }
            else
            {
                Code += '1';
            }
            index1 = index;
        }
        reverse(Code.begin(), Code.end());//翻转字符串
        iter->second.Code = Code;//令当前map的value值为当前的字符串
    }
}
int createhuffmantree(MyStruct huffman[N], map<char, MyStruct1> & key)//创建哈弗曼树
{
    string Code;
    FILE* fp = NULL;//需要注意
    /*fp = fopen(PATHIN, "w");  //创建文件
    fclose(fp);*/
    fp = fopen(PATHEN, "w");  //创建文件
    fclose(fp);
    fp = fopen(PATHRE, "w");  //创建文件
    fclose(fp);
    createbase();
    ifstream OpenFile(PATHIN);
    int n = 1;
    if (!OpenFile)//异常退出
    {
        cout << "error" << endl;
        return 0;
    }
    while (!OpenFile.eof())//当文件不为0的时候
    {
        OpenFile >> huffman[n].code >> huffman[n].weight;
        if (huffman[n].code == '#')//空格代替为#
            huffman[n].code = ' ';
        key[huffman[n].code].index = n;
        n++;
    }
    n--;
    int k = n;
    for (int i = n+1; i <=2 * n-1; i++)
    {
        int min1 = INF, min2 = INF;//找到最小的两个值
        int index1, index2;
        for (int j = 1; j <= k; j++)
        {
            if (huffman[j].weight <min1 && huffman[j].flag ==0)
            {
                min1 = huffman[j].weight;
                index1 = j;
            }
        }
        huffman[index1].flag = 1;
        for (int j = 1; j <= k; j++)
        {
            if (huffman[j].weight <min2 && huffman[j].flag == 0)
            {
                min2 = huffman[j].weight;
                index2 = j;
                
            }
        }
        huffman[index2].flag = 1;
        huffman[i].weight = huffman[index1].weight + huffman[index2].weight;//构建哈弗曼树
        huffman[i].flag = 0;
        huffman[i].left = index1;
        huffman[i].right = index2;
        huffman[index1].parent = i;
        huffman[index2].parent = i;
        k++;
    }
    OpenFile.close();
    return 1;
}
void printzimuCode(map<char, MyStruct1> & key)//打印字母编码
{
    for (iter = key.begin(); iter != key.end(); iter++)
    {
        cout << iter->first << " " << iter->second.Code << endl;
    }
}
void changeCode(MyStruct huffuman[N], map<char, MyStruct1> & key)//转换字母编码
{
    ofstream out(PATHEN);
    string k, ans;
    cout << "请输入要转换的字母" << endl;
    getchar();
    getline(cin, k);
    for (int i = 0; i < k.size(); i++)
    {
        ans += key[k[i]].Code;
    }
    out << ans;
    out.close();
    cout << "转换完成" << endl;
    cout << "是否要查看输出结果?" << endl;
    cout << "【1】查看" << endl << "【2】退出" << endl;
    int od;
    cin >> od;
    if (od == 1)
    {
        int cnt = 0;
        ifstream out(PATHEN);
        while (!out.eof() && cnt++ < ans.size())
        {
            char temp;
            out >> temp;
            cout << temp;

        }
        cout << endl;
    }
    else
    {
        cout << endl;
        out.close();
        return;
    }
    out.close();

}
void reductionCode(MyStruct huffuman[N], map<char, MyStruct1> & key)//编码转换字母
{
    ofstream out("F:\\decoding.txt");
    string k;
    cout << "请输入要转换的编码" << endl;
    getchar();
    getline(cin, k);
    int head = 1;
    for (int i = 1;; i++)
    {
        if (huffuman[i].parent == 0)
        {
            head = i;
            break;
        }
    }
    int j = head;
    string ans;
    for (int i = 0; i < k.size(); i++)
    {
        if (k[i] == '0')
        {
            j = huffuman[j].left;
        }
        else if (k[i] == '1')
        {
            j = huffuman[j].right;
        }
        if (huffuman[j].left == 0 && huffuman[j].right == 0)
        {
            out << huffuman[j].code;
            j = head;
        }
    }
    out.close();//注意不关闭就出错
    cout << "转换完成" << endl;
    cout << "是否要查看输出结果?" << endl;
    cout << "【1】查看" << endl << "【2】退出" << endl;
    int od;
    cin >> od;
    if (od == 1)
    {
        string temp1;
        ifstream out("F:\\decoding.txt");
        while (!out.eof())
        {
            char temp;
            out >> temp;
            temp1 += temp;
        }
        for (int j1 = 0; j1 < temp1.size() - 1; j1++)
        {
            cout << temp1[j1];
        }
        cout << endl;
    }
    else
    {
        cout << endl;
        out.close();
        return;
    }
    out.close();
}
void order()//指令集
{
    cout << "主 菜 单" << endl;
    cout << "输入对应数字实现相应功能" << endl;
    cout << "【1】打印字母编码" << endl;
    cout << "【2】任意英文字母转换编码" << endl;
    cout << "【3】任意编码转英文字母" << endl;
    cout << "【4】展示指令集" << endl;
    cout << "【5】文件目录说明" << endl;
    cout << "【0】退出程序" << endl;
}
void choice(MyStruct huffman[N], map<char, MyStruct1> & key)//选择功能
{
    if (!createhuffmantree(huffman, key))
    {
        cout << "创建失败" << endl;
        exit(0);
    }
    else
    {
        cout << "创建成功" << endl;
        order();
        while (1)
        {
            int x;
            cin >> x;
            if (x == 1)
            {
                cout << "字母编码如下:" << endl;
                createCode(huffman, key);
                printzimuCode(key);
            }
            else if (x == 2)
            {
                changeCode(huffman, key);
            }
            else if (x == 3)
            {
                reductionCode(huffman, key);
            }
            else if (x == 4)
            {
                order();
            }
            else if (x == 0)
            {
                exit(0);
            }
            else if (x == 5)
            {
                cout << "文件目录默认在F盘目录下" << endl;
                cout << "英文转换编码的文件为: " << "encoding.txt " << endl;
                cout << "编码转换英文的文件为: " << "decoding.txt " << endl;
            }
            else
            {
                cout << "指令不存在,请重新输入" << endl;
            }
            cout << "请输入指令" << endl;
        }
    }
}
int main()
{
    MyStruct huffman[N];
    memset(huffman, 0, sizeof(huffman));//如果直接放在函数里,无法初始化
    map<char, MyStruct1>key;//通过索引快速找到坐标,储存编码
    choice(huffman, key);
    return 0;
}
最后修改:2019 年 07 月 26 日 08 : 24 PM