【问题标题】:How to display our encoded text in a file using Huffman Encoding如何使用 Huffman 编码在文件中显示我们的编码文本
【发布时间】:2022-06-15 07:48:31
【问题描述】:

在我的霍夫曼算法项目中,到目前为止,我已经为输入文件的每个字符生成了代码。我还将字符及其相应的代码存储在无序映射中。现在,我想读取我们的输入字符串,并打印输出文件中每个字符的相应代码。但是,以字符串格式打印代码不会压缩文件。我想将我的字符串代码转换为位格式。我知道我们需要使用字节缓冲区,但我不知道如何将这个概念应用到我的代码中。任何帮助将不胜感激。

#include<iostream>
#include<string>
#include<queue>
#include<vector>
#include<bitset>
#include<fstream>
#include<unordered_map>
#include<map>
using namespace std;

struct node
{
    char c; //character in the string
    int f; //Frequency of character in the string
    node* next;
    node* left, * right; //left and right child of binary tree respectively

    node()
    {
        f = 0;
        left = NULL;
        right = NULL;
        c = NULL;
        next = NULL;

        
    }
};


struct compare {
public:
    bool operator()(node* a, node* b) // overloading both operators 
    {
        
        return a->f > b->f; //To maintain the order of min heap priority queue
    }
};
class Huffman
{
    string filename; //The name of the file we want to encode
    string text; //The text that will be encoded
    priority_queue<node*, vector<node*>, compare> pq; //Priority queue that will contian characters of our string and their frequency
    string encoded;
    unordered_map <char, string> um;
public:
    Huffman()
    {
        
        text = "";
        encoded = "";
    }

    void FileRead()
    {
        cout << "Enter the name of the file you want to encode:";
        cin >> filename;
        fstream readfile(filename, fstream::in);
        getline(readfile, text, '\0');

        cout << text << endl;
        readfile.close();
    }

    

    //Function which will calculate the frequency of characters in the string entered by the user
    void CharacterFrequency()
    {
        
        for (int i = 0; i < text.length(); i++)
        {
            int sum = 0;
            for (int j = 0; j < text.length(); j++)
            {

                if (j < i and text[i] == text[j])
                {
                    break;
                }


                    if (text[i] == text[j])
                    {
                        sum++;
                        
                        
                    } 
                    
                    
                
            }

            if (sum != 0)
            {
                PriorityQueue(text[i], sum);
            }
        }

            
            
        

    }

    // This will push our characters and their frequencies into our STL min heap priority queue
    void PriorityQueue(char ch, int freq)
    {
        
        node* n=new node; //pointer of type node is created
        n->c = ch; //Pointer stores character
        n->f = freq; //Pointer stores frequency of the character
        pq.push(n); //The node is pushed into the priority queue
        

        
    }

    //Will display the whole priority queue. All of the elements will be popped from it as a result.
    void PriorityQueueDisplay()
    {
        while (!pq.empty())
        {
            cout << (pq.top())->c<<" "<<(pq.top())->f << endl;
            pq.pop();
        }
    }


    //This function will create our Huffman Tree from a priority queue
    void HuffmanTree()
    {
        node* n1, * n2; //The nodes that will be popped each time from the priority queue

        //This loop will continue to pop out two nodes from the priority queue until only one nodes is left
        //in the priority queue
        while (pq.size()!=1)
        {
            n1 = pq.top();
            pq.pop();
            n2 = pq.top();
            pq.pop();
            node* z = new node; //Creation of new node of Huffman tree
            z->left = n1;
            z->right = n2;
            z->f = (n1->f) + (n2->f); //Storing sum of the two popped nodes in Huffman tree node
            z->c = '&'; //Assigning the new node a character that is not used in formal speech
            pq.push(z); //Pushing the node into the priority queue again
            
        }

        node* root = pq.top(); //Making the last node the root node
        EncodeAndPrintCodes(root,encoded); //Passing the root node and a string that will encode each character of our inputted string
    }

    //This function will recursively search for a character in the string, and will print it's corresponding code.
    //It will do this for all our characters
    void EncodeAndPrintCodes(node* root,string en)
    {
        
        if (root == NULL)
        {
            
            return ;
        }

        if (root->c != '&')
        {
            //cout << root->c << ":" << en;
            StoreinMap(root->c, en);
            
        }
        
        EncodeAndPrintCodes(root->left, en + "0");
        EncodeAndPrintCodes(root->right, en + "1");
        
        
        
    }

    //Will convert our code in string to bitstream and then store it in a text file
    void CompressedFile(char ch, string code)
    {
        
        ofstream compressed;
        compressed.open("CompressedFile.txt", ios::app | ios::out);
    }

    void StoreinMap(char ch, string code)
    {
        
        
        um.emplace(pair<char, string>(ch,code));
        
    }

    /*void DisplayEncoded()
    {
        cout << encoded;
    }*/



    //Displays the size of the priority queue
    void DisplaySize()
    {
        cout<<pq.size();
    }
};

int main()
{
    Huffman obj;
    obj.FileRead();
    obj.CharacterFrequency();
    //obj.PriorityQueueDisplay();
    obj.HuffmanTree();
    //obj.DisplaySize();
    //obj.DisplayEncoded();
    //obj.CompressedFile();
    return 0;
}

【问题讨论】:

  • 你知道怎么把8位变成一个字节吗?
  • 如果你的问题真的是关于“转换一个字符串”,你可能会限制你的回答,首先要求每个人阅读和理解超过 200 行代码。 minimal reproducible example 会帮助你,因为大部分代码与你的问题无关。
  • 在最简单的形式中,您可以只拥有一个保存一个字节的变量和一个带有当前存储在该字节中的位数的第二个变量。对于您要写入的每个代码,将其位添加到字节中,当字节达到 8 位时,将其写入文件并将其重置回 0 并将计数器重置为 0。您可以通过在以下位置写入更多字节来提高效率时间,但相同的基本结构适用
  • char c; c = NULL; - 不要那样做。 c 不是指针。

标签: c++ stl huffman-code


【解决方案1】:

复制自this answer,这是一种将位写入字节文件的方法。您有一个位缓冲区,包括:

unsigned long bitBuffer = 0;
int bitcount = 0;

将 value 中的 bits 位添加到缓冲区中:

bitBuffer |= value << bitCount;
bitcount += bits;

写入和删除可用字节:

while (bitCount >= 8) {
    writeByte(bitBuffer & 0xff);
    bitBuffer >>>= 8;
    bitCount -= 8;
}

最后,您需要写入位缓冲区中剩余的所有位。解码时,您需要注意不要将最后一个字节中的任何填充位解释为不是的数据。为此,您需要在数据中添加一个结束标记。

一些侧面cmets。不知何故,您将字符频率的 O(n) 计算变成了 O(n^2) 计算!你应该再考虑一下。不要定义特殊字符值。您应该能够压缩任何字节序列。如果输入达到零字节,您对getline() 的使用将停止读取输入。使用rdbuf()。您使用&amp; 作为节点的指示符是因为您认为该字符“未在正式演讲中使用”是错误的。 (它通常用于书写。)如果输入中有一个&符号,您的程序将崩溃,试图访问一个未初始化的指针。使用left 作为节点或叶子的指示符,如果它是叶子,则将其设置为nullptr

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 2014-03-20
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多