C++项目基于HuffmanTree实现文件的压缩与解压缩功能

yizhihongxing

标题:C++项目基于HuffmanTree实现文件的压缩与解压缩功能

一、HuffmanTree基本概念

Huffman编码是一种无损压缩算法,主要思想是利用频率较高的字符使用较短的二进制编码,频率较低的字符使用较长的二进制编码,从而实现压缩目的。

Huffman树是一种高效的实现Huffman编码的数据结构,它是一棵带权树,其中每个叶子结点代表一个字符,其权值为该字符在文本中出现的频率。利用HuffmanTree的思想,我们可以在不降低原始数据质量的情况下实现对文本的压缩。

二、项目实现过程

下面介绍C++项目基于HuffmanTree实现文件的压缩与解压缩功能的详细实现步骤。

1. 遍历文件并生成字符频率map

首先,我们需要遍历所要压缩的文件,并统计文件中每个字符出现的频率。这里使用std::map<char, int>来记录字符与出现频率的对应关系。

示例代码:

#include <fstream>
#include <map>

// 遍历文件并生成字符频率map
std::map<char, int> getCharFrequency(std::string filePath) {
    std::map<char, int> frequencyMap;
    std::ifstream file(filePath, std::ios::binary);
    char c;
    while (file.get(c)) {
        ++frequencyMap[c];
    }
    return frequencyMap;
}

2. 根据字符频率map构建Huffman树

获取到字符频率map后,我们需要构建Huffman树。具体实现方法为:

  1. 将频率map中的字符和权重都存入一个vector中;
  2. 构建小根堆,按照每个字符出现频率的大小进行排序;
  3. 从小根堆获取最小的两个节点,创建一个新的父节点,权重为两个节点的权重之和,并将父节点插入回小根堆;
  4. 重复第三步,直到小根堆只剩下一个节点,即Huffman树的根节点。

示例代码:

#include <queue>
#include <vector>

// Huffman树节点结构体
struct Node {
    char character;
    int weight;
    Node *leftChild;
    Node *rightChild;
    Node(char c, int w, Node *l = nullptr, Node *r = nullptr) : character(c), weight(w), leftChild(l), rightChild(r) {}
};

// 小根堆比较器
struct compareNode {
    bool operator()(const Node *a, const Node *b) { return a->weight > b->weight; }
};

// 根据字符频率map构建Huffman树
Node *buildHuffmanTree(std::map<char, int> frequencyMap) {
    std::priority_queue<Node *, std::vector<Node *>, compareNode> minHeap;
    for (const auto &frequency : frequencyMap) {
        minHeap.push(new Node(frequency.first, frequency.second));
    }
    while (minHeap.size() > 1) {
        Node *leftChild = minHeap.top();
        minHeap.pop();
        Node *rightChild = minHeap.top();
        minHeap.pop();
        minHeap.push(new Node('\0', leftChild->weight + rightChild->weight, leftChild, rightChild));
    }
    return minHeap.top();
}

3. 生成Huffman编码表

生成Huffman编码表的过程是将Huffman树进行遍历,并在遍历过程中记录下每个字符的Huffman编码。在这里我们使用递归的方式来进行Huffman树的遍历。

示例代码:

#include <unordered_map>

// 生成Huffman编码表的递归函数
void buildHuffmanCode(Node *node, std::string code, std::unordered_map<char, std::string> &codeTable) {
    if (node->leftChild == nullptr && node->rightChild == nullptr) {
        codeTable[node->character] = code;
        return;
    }
    buildHuffmanCode(node->leftChild, code + "0", codeTable);
    buildHuffmanCode(node->rightChild, code + "1", codeTable);
}

// 生成Huffman编码表
std::unordered_map<char, std::string> buildHuffmanCodeTable(Node *huffmanTree) {
    std::unordered_map<char, std::string> codeTable;
    buildHuffmanCode(huffmanTree, "", codeTable);
    return codeTable;
}

4. 将文件按照Huffman编码进行压缩

获取到Huffman编码表后,我们就可以将所要压缩的文件按照这个编码表进行压缩。具体实现方法是:

  1. 遍历文件,获取到每个字符对应的Huffman编码;
  2. 将Huffman编码依次存入一个字符串中,每8个二进制位组成一个字节,并将其写入到文件中;
  3. 在文件的开头写入字符频率map,以便解压缩时可以重新生成Huffman树。

示例代码:

#include <bitset>
#include <fstream>

// 将文件按照Huffman编码进行压缩
void compressFile(std::string sourcePath, std::string targetPath) {
    auto frequencyMap = getCharFrequency(sourcePath);
    auto huffmanTree = buildHuffmanTree(frequencyMap);
    auto codeTable = buildHuffmanCodeTable(huffmanTree);
    std::ifstream inputFile(sourcePath, std::ios::binary);
    std::ofstream outputFile(targetPath, std::ios::binary);
    // 写入字符频率map
    size_t frequencyMapSize = frequencyMap.size();
    outputFile.write((char *)&frequencyMapSize, sizeof(size_t));
    for (const auto &frequency : frequencyMap) {
        outputFile.write(&frequency.first, sizeof(char));
        outputFile.write((char *)&frequency.second, sizeof(int));
    }
    // 将文件按照Huffman编码进行压缩
    std::string bitString;
    char c;
    while (inputFile.get(c)) {
        bitString += codeTable[c];
        while (bitString.length() >= 8) {
            std::bitset<8> byte(bitString.substr(0, 8));
            outputFile.write((char *)&byte, sizeof(char));
            bitString.erase(0, 8);
        }
    }
    if (!bitString.empty()) {
        bitString += std::string(8 - bitString.length() % 8, '0');
        std::bitset<8> byte(bitString.substr(0, 8));
        outputFile.write((char *)&byte, sizeof(char));
    }
}

5. 解压缩文件

将文件按照Huffman编码进行压缩后,我们需要实现对其进行解压缩。具体实现方法是:

  1. 读取文件开头的字符频率map,重新生成Huffman树;
  2. 加载文件中的Huffman编码,并根据Huffman编码还原出文件中的原始字符。

示例代码:

#include <fstream>

// 解压缩文件
void decompressFile(std::string sourcePath, std::string targetPath) {
    std::ifstream inputFile(sourcePath, std::ios::binary);
    size_t frequencyMapSize;
    // 读取字符频率map
    inputFile.read((char *)&frequencyMapSize, sizeof(size_t));
    std::map<char, int> frequencyMap;
    for (size_t i = 0; i < frequencyMapSize; ++i) {
        char c;
        int frequency;
        inputFile.read(&c, sizeof(char));
        inputFile.read((char *)&frequency, sizeof(int));
        frequencyMap[c] = frequency;
    }
    // 构建Huffman树并重新生成Huffman编码表
    auto huffmanTree = buildHuffmanTree(frequencyMap);
    auto codeTable = buildHuffmanCodeTable(huffmanTree);
    std::ofstream outputFile(targetPath, std::ios::binary);
    // 解压缩文件
    std::string bitString;
    char c;
    while (inputFile.get(c)) {
        std::bitset<8> byte(c);
        bitString += byte.to_string();
    }
    if (bitString.length() % 8 != 0) {
        bitString.erase(bitString.length() - (bitString.length() % 8));
    }
    Node *currentNode = huffmanTree;
    for (size_t i = 0; i < bitString.length(); ++i) {
        if (bitString[i] == '0') {
            currentNode = currentNode->leftChild;
        } else {
            currentNode = currentNode->rightChild;
        }
        if (currentNode->leftChild == nullptr && currentNode->rightChild == nullptr) {
            outputFile.write(&currentNode->character, sizeof(char));
            currentNode = huffmanTree;
        }
    }
}

三、示例说明

下面给出两个压缩和解压缩文件的示例:

示例一

压缩文件test.txt并将其解压到output.txt中。

std::string sourcePath = "test.txt";
std::string compressedPath = "compressed.bin";
std::string decompressedPath = "output.txt";
compressFile(sourcePath, compressedPath);
decompressFile(compressedPath, decompressedPath);

示例二

压缩文件test.mov并将其解压到output.mov中。

std::string sourcePath = "test.mov";
std::string compressedPath = "compressed.bin";
std::string decompressedPath = "output.mov";
compressFile(sourcePath, compressedPath);
decompressFile(compressedPath, decompressedPath);

以上就是C++项目基于HuffmanTree实现文件的压缩与解压缩功能的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++项目基于HuffmanTree实现文件的压缩与解压缩功能 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Linux平台安装MongoDB及使用Docker安装MongoDB

    Linux平台安装MongoDB及使用Docker安装MongoDB 简介 MongoDB 是一个 NoSQL 数据库,它的灵活性、高效性使其成为互联网数据存储和查询的首选方案。MongoDB 具有良好的数据可扩展性,支持水平和垂直扩展。本文将介绍如何在 Linux 平台上安装 MongoDB 和使用 Docker 安装 MongoDB。 在 Linux 平…

    其他 2023年3月28日
    00
  • C语言数据的存储专项分析

    C语言数据的存储专项分析攻略 1. 理解数据存储 在C语言中,数据存储是指将数据存储在计算机内存中的过程。了解数据存储的原理和机制对于编写高效的C程序至关重要。 2. 数据类型的存储 C语言提供了多种数据类型,每种类型在内存中占用的空间大小不同。以下是一些常见的数据类型及其存储大小: int:整数类型,通常占用4个字节。 float:单精度浮点数类型,通常占…

    other 2023年8月2日
    00
  • Ruby 面向对象知识总结

    以下是关于Ruby面向对象知识的详细攻略: 类和对象 在Ruby中,使用class关键字定义一个类,并使用new方法创建一个对象。 class Person def initialize(name) @name = name end def say_hello puts \"Hello, #{@name}!\" end end perso…

    other 2023年10月17日
    00
  • 守望先锋自动以模式都有什么_七大热门自定义模式详解

    守望先锋自动匹配模式 守望先锋拥有多种不同的自动以模式,玩家可以根据自己的需要进行选择。以下是七种热门的自定义模式: 1. 控制点模式 控制点模式是寻找和守卫控制点的模式,玩家需要占领地图上的控制点并守卫它们以获得胜利。每个控制点都需要一定时间才能被占领,而且如果敌方队员也在控制点上,那么这个时间会大大增加。此模式需要玩家有较高的战略意识和团队合作精神。 示…

    other 2023年6月25日
    00
  • 浅谈java什么时候需要用序列化

    浅谈Java什么时候需要用序列化 序列化是将对象转换为字节流的过程,可以用于对象的存储、传输和持久化。在Java中,当满足以下情况时,通常需要使用序列化: 对象需要在网络中传输:当需要将对象通过网络传输给其他计算机或进程时,需要将对象序列化为字节流,以便在网络上传输。例如,客户端和服务器之间的通信,可以使用序列化将对象发送给服务器或客户端。 示例说明1:将对…

    other 2023年10月15日
    00
  • css各种鼠标手型集合

    以下是详细讲解“CSS各种鼠标手型集合的完整攻略”的标准Markdown格式文本,包含两个示例说明: CSS各种鼠标手型集合攻略 在Web开发中,鼠标手型是一个重要的交互元素。CSS提供了各种鼠标手型,可以根据需要不同的鼠标手型。本攻略将介绍如何使用CSS设置各种鼠标手型。 步骤一:使用cursor属性 可以使用的cursor属性来设置鼠标手型。cursor…

    other 2023年5月10日
    00
  • Java中对象都是分配在堆上吗?你错了!

    该话题是关于Java中对象是否都分配在堆上的问题。事实上,不是所有的对象都是完全分配在堆上的,有些对象可能会分配在栈上或者其他区域。 分配在堆上的对象 Java中的对象的实例都是在堆上分配的。在一个程序执行的时候,堆被分成多个区域,比如新生代和老年代。对于普通的Java对象,它们都是分配在堆上的,比如: // 创建一个Person对象 Person pers…

    other 2023年6月26日
    00
  • 百度音乐mac版怎么下载音乐 百度音乐mac下载地址

    百度音乐mac版下载音乐攻略 百度音乐是一款流行的音乐播放器和下载工具,它提供了丰富的音乐资源供用户在线收听和下载。以下是在Mac电脑上下载音乐的详细攻略。 步骤一:下载百度音乐mac版 首先,你需要下载并安装百度音乐的mac版。你可以通过以下步骤进行下载: 打开你的浏览器,访问百度音乐的官方网站。 在网站上找到并点击下载按钮,选择mac版进行下载。 下载完…

    other 2023年8月4日
    00
合作推广
合作推广
分享本页
返回顶部