我能够只使用队列库为霍夫曼编码编写代码。但是当我保存我的文件进行压缩时,它给出了比原始文件更大的字节大小。
例如
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*。
2条答案
按热度按时间az31mfrm1#
您要向输出写入8位/位,因此它比预期值大8倍。您希望写入1位/位。要写入位,您需要将它们逐个累加到字节缓冲区中,直到达到8位,然后写入该字节。最后,写入剩余位。使用位运算符
<<
和|
将位放入字节缓冲区。例如,对于每个等于0或1的bit
:您的代码还有许多其他问题。
1.因为
c
是有符号字节类型,所以freq[c]++;
对于字节数大于127的输入将失败,因为c
将为负。您需要int c;
而不是char c
。1.使用
while(!fp.eof())
将导致得到-1
作为最后一个字符,这是EOF指示,并且再次用负数索引数组。1.第一次读取文件时使用了一系列
get()
,这是正确的。但是第二次读取文件时,使用了一个getline()
。这只获取了第一行,并且省略了新行字符。两次读取文件的方式相同,使用了一系列get()
。1.你只是在写代码。在这些代码之前没有霍夫曼代码的描述,所以解码器无法理解你发送的比特。一旦你把它固定为每比特发送一个比特而不是每比特发送一个字节,你的输出将比数据实际上可以压缩的长度“小”。当你添加树时,输入和输出将大约是相同的长度。
1.每次你想编码一个字符时,你都在遍历整个树!你需要通过遍历树 * 一次 * 来制作一个代码表,然后使用这个表来编码。
1.无法知道有多少字符已被编码,这将导致最后一个字节中任何额外位的不确定性。您需要在编码字符之前发送字符数,或者在编码流结束指示符时再包含一个符号。
f5emj3cl2#
你在
encoded
中的是一个0和1的字符串。它们本身就是字符。你可能想把这个字符串转换成二进制然后存储它?如果你用字符(一个字节)来存储0和1,它会占用更多的空间。它不是用1位来存储数字,而是用1字节。所以如果你把数据转换成位,它应该是(44/8)+1