哈夫曼编码系统 C++实现

最近的数据结构大作业…
其中涉及到了很多,像一些哈夫曼树的编码、译码,以及树的二叉树形式的存储及恢复。。
[基本要求]
一个完整的系统应具有以下功能:
(1)I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件htmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码写入文件CodePrint中。
(5)T:印哈夫曼树(Tree Printing)。将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。

注释很详细了,也花了不少时间。这些我当时也是参考了许多他人的资料,希望我这篇博客能够在总结前人的基础上,让大家更好、更综合地理解这一个实现过程。
我自认为我的编码风格还是比较容易懂的,函数名字也都是有意义的,如果看下来的话其实不会太吃力,同时很多地方的参考我也在前面列举了,如果有疑问或者是有问题,欢迎在评论区留言。

参考:

  1. 哈夫曼编码C++实现
  2. 二叉树的文件存储和读取
  3. c++按行读取文件的方式
  4. c++ofstream与c风格fwrite的一个小区别
  5. c++字符串按空格分割
    这里是用了头文件<sstream>处理的,相对简单一些,但是限于以空格分割, 更复杂的请搜索split函数。
  6. 上面的空格分割字符串存在只能处理一行的问题,我在其进行了改进
  7. c++ string类型与基本数值类型 的互相转换
  8. c++ 头文件中stringstream流的用法的一些补充
  9. access函数:检测文件是否存在/是否具有读/写权限
  10. string 与const char*、char*、char[]之间相互转换
  11. 一次读入整个txt文件到一个string中
  12. 在fstream流中新手可能把模式ios::a|ios::b中的"|“写成”||",会导致文件无法打开

注:此代码是在VS2019下运行,因有一些函数可能与标准库不一样,如下面的_access函数,如果你在你编译器上报错,请把这些带有"_"的函数的前缀“_”去掉即可。

// 赫夫曼编码系统.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
#include <vector>
#include <map>
#include <algorithm>
#include<io.h> //调用access函数确认文件是否存在
#include<windows.h>
using namespace std;

const string hfmTree = "hfmTree.txt";
const string tobeEncoding = "ToBeTran.txt";
const string EncodingResult = "CodeFile.txt";
const string DecodingResult = "TextFile.txt";
const string CodePrin = "CodePrin.txt";
const string TreePrin = "TreePrin.txt";

typedef double weighttype;
//string对象转换为数值类型
template <class Type>
Type stringToNum(const string& str) {
   
   
    istringstream iss(str);
    Type num;
    iss >> num;
    return num;
}
struct HFMNode
{
   
   
    char key;
    weighttype weight;
    HFMNode* left, * right;
    HFMNode(char k, weighttype w) :key(k), weight(w), left(nullptr), right(nullptr) {
   
   };
    HFMNode(weighttype w) :key('/0'), weight(w), left(nullptr), right(nullptr) {
   
   };
    //第二个构造函数用于存储合并两个树的父节点,这时其key应该是被禁用,这里用'\0'
};
typedef HFMNode* HFMNodeP;
typedef map<int, HFMNodeP> NodeMap;//节点的位置为key,节点的指针为值
typedef int Position;
//把树存储在文件中
struct HFMNodeFile {
   
   
    char key; //节点值
    weighttype weight;
    Position p; //节点在完全二叉树中的位置
};
bool compare(HFMNode* e1, HFMNode* e2) {
   
   
    return e1->weight < e2->weight;
}//构建小顶堆,方便每次取两个最小值
class HFMTree {
   
   
public:
    HFMTree() {
   
   
        root = nullptr;
        count = 0;
    }
    ~HFMTree() {
   
   
        ClearDecodeTree();
    }
    //建立哈夫曼树
    HFMNode* BuildHFMTree(const map<char, double>& KVmap) {
   
   
        vector<HFMNode*> HFMNodes;
        for (auto itr = KVmap.begin(); itr != KVmap.end(); ++itr) {
   
   
            HFMNodes.push_back(new HFMNode(itr->first, itr->second));
            ++count;
        }

        make_heap(HFMNodes.begin(), HFMNodes.end(), compare);

        while (HFMNodes.size() > 1) {
   
   
            HFMNode* right = HFMNodes.front();
            pop_heap(HFMNodes.begin(), HFMNodes.end(), compare);
            HFMNodes.pop_back();

            HFMNode* left = HFMNodes.front();
            pop_heap(HFMNodes.begin(), HFMNodes.end(), compare);
            HFMNodes.pop_back();

            HFMNode* parent = new HFMNode(left->weight + right->weight)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值