c++ 我的压缩文件比原始文件大

k4ymrczo  于 2023-01-10  发布在  其他
关注(0)|答案(2)|浏览(156)

我能够只使用队列库为霍夫曼编码编写代码。但是当我保存我的文件进行压缩时,它给出了比原始文件更大的字节大小。
例如
filesize.txt有17个字节,其中包含字符串“Stressed-desserts”,而
压缩文件. bin具有44个字节,其包含原始文件“01111011000011100011001100110011110010010111”的霍夫曼代码。
这是我的全部代码

#include <iostream>
#include <queue>
#include <fstream>

using namespace std;

struct HuffNode{
    int my_Frequency;
    char my_Char;
    string my_Code;
    HuffNode* my_Left;
    HuffNode* my_Right;
};

//global variables
int freq[256] = {0};
string encoded = "";
string filename;

//Comparing the frequency in the priority queue
struct compare_freq {
    bool operator()(HuffNode* l, HuffNode* r) {
        return l->my_Frequency > r->my_Frequency;
    }
};

priority_queue <HuffNode*, vector<HuffNode*>, compare_freq> freq_queue;

//get the file from user
string get_file_name()
{
    cout << "Input file name to compress: ";
    cin >> filename;
    return filename;
}

//Scan the file to be compressed and tally all the occurence of all characters.
void file_getter()
{
    fstream fp;
    char c;

    fp.open(get_file_name(), ios::in);
    if(!fp)
    {
        cout << "Error: Couldn't open file " << endl;
        system("pause");
    }
    else
    {
        while(!fp.eof())
        {
            c = fp.get();
            freq[c]++;
        }
    }
    fp.close();
}

//HuffNode to create a newNode for queue containing the letter and the frequency
HuffNode* set_Node(char ch, int count)
{
    HuffNode* newNode = new HuffNode;
    newNode->my_Frequency = count;
    newNode->my_Char = ch;
    newNode->my_Code = "";
    newNode->my_Right = nullptr;
    newNode->my_Left = nullptr;
    return newNode;
}

//Sort or Prioritize characters based on numbers of occurences in text.
void insert_Node(char ch, int count)
{
    //pass the ch and count to the newNodes for queing
    freq_queue.push(set_Node(ch, count));
}

void create_Huffman_Tree()
{
    HuffNode* root;
    file_getter();
    
    //insert the characters in the their frequencies into the priority queue
    for(int i = 0; i < 256; i++)
    {
        if(freq[i] > 0)
        {
            insert_Node(char(i), freq[i]);
        }
    }

    //build the huffman tree
    while(freq_queue.size() > 1)
    {
        //get the two highest priority nodes
        HuffNode* for_Left = freq_queue.top();
        freq_queue.pop();
        HuffNode* for_Right = freq_queue.top();
        freq_queue.pop();

        //Create a new HuffNode with the combined frequency of the left and right children
        int freq = for_Left->my_Frequency + for_Right->my_Frequency;
        char ch = '$';
        root = set_Node(ch, freq);
        root->my_Left = for_Left;
        root->my_Right = for_Right;

        //Insert the new node into the priority_queue.
        freq_queue.push(root);
    }

    // The remaining HuffmanNode in the queue is the root of the Huffman tree
    root = freq_queue.top();
}

void preOrderTraverse(HuffNode* root, char c, string code) 
{
    if (root == nullptr) {
        // If the tree is empty, return
        return;
    } 
    if (root->my_Char == c) 
    {
        // If the current HuffmanNode is a leaf HuffmanNode, print the code for the character.
        root->my_Code = code;
        encoded += code;
        return;
    } 
    // Otherwise, recurse on the left and right children
    preOrderTraverse(root->my_Left, c, code + "0");
    preOrderTraverse(root->my_Right, c, code + "1");
}

void encode_File(string ccode)
{
    HuffNode* root = freq_queue.top();
    for(int i = 0; i < ccode.length(); i++)
    {
        char c = ccode[i];
        string code = "";
        preOrderTraverse(root, c, code);
    }
}

void save_Huffman_Code()
{
    fstream fp, fp2;
    fp.open("Compressed_file.bin", ios::out);
    fp2.open(filename, ios::in);
    
    string ccode;
    getline(fp2, ccode);
    encode_File(ccode);

    fp << encoded;
    
    fp.close();
    fp2.close();
}

int main()
{
    create_Huffman_Tree();
    HuffNode* root = freq_queue.top();
    save_Huffman_Code();
}

我应该得到一个压缩文件,它的字节大小比原来的小。我试图不使用位操作、无序 * Map或Map来编写代码。我只对程序使用priority_queue*。

az31mfrm

az31mfrm1#

您要向输出写入8位/位,因此它比预期值大8倍。您希望写入1位/位。要写入位,您需要将它们逐个累加到字节缓冲区中,直到达到8位,然后写入该字节。最后,写入剩余位。使用位运算符<<|将位放入字节缓冲区。例如,对于每个等于0或1的bit

unsigned buf = 0, n = 0;
...
    buf |= bit << n;
    if (++n == 8) {
        fp.put(buf);
        buf = n = 0;
    }
...
if (n)
    fp.put(buf);

您的代码还有许多其他问题。
1.因为c是有符号字节类型,所以freq[c]++;对于字节数大于127的输入将失败,因为c将为负。您需要int c;而不是char c
1.使用while(!fp.eof())将导致得到-1作为最后一个字符,这是EOF指示,并且再次用负数索引数组。
1.第一次读取文件时使用了一系列get(),这是正确的。但是第二次读取文件时,使用了一个getline()。这只获取了第一行,并且省略了新行字符。两次读取文件的方式相同,使用了一系列get()
1.你只是在写代码。在这些代码之前没有霍夫曼代码的描述,所以解码器无法理解你发送的比特。一旦你把它固定为每比特发送一个比特而不是每比特发送一个字节,你的输出将比数据实际上可以压缩的长度“小”。当你添加树时,输入和输出将大约是相同的长度。
1.每次你想编码一个字符时,你都在遍历整个树!你需要通过遍历树 * 一次 * 来制作一个代码表,然后使用这个表来编码。
1.无法知道有多少字符已被编码,这将导致最后一个字节中任何额外位的不确定性。您需要在编码字符之前发送字符数,或者在编码流结束指示符时再包含一个符号。

f5emj3cl

f5emj3cl2#

你在encoded中的是一个0和1的字符串。它们本身就是字符。你可能想把这个字符串转换成二进制然后存储它?
如果你用字符(一个字节)来存储0和1,它会占用更多的空间。它不是用1位来存储数字,而是用1字节。所以如果你把数据转换成位,它应该是(44/8)+1

相关问题