Pagini recente » Cod sursa (job #655209) | Cod sursa (job #1313911) | Cod sursa (job #1706267) | Cod sursa (job #704369) | Cod sursa (job #2612053)
#include <fstream>
#include <queue>
#include <iostream>
#include <vector>
#include <cctype>
using namespace std;
class InParser {
private:
static const int buffSZ = (1 << 15);
ifstream File;
int buffPos;
char buff[buffSZ];
void _advance() {
if (++buffPos == buffSZ) {
File.read(buff, buffSZ);
buffPos = 0;
}
}
public:
InParser(const char *FileName) {
buffPos = buffSZ - 1;
File.open(FileName);
}
InParser& operator >>(int &no) {
while (!isdigit(buff[buffPos]))
_advance();
no = 0;
while (isdigit(buff[buffPos])) {
no = no * 10 + buff[buffPos] - '0';
_advance();
}
return *this;
}
};
class OutParser {
private:
static const int buffSZ = (1 << 15);
ofstream File;
char buff[buffSZ];
int buffPos;
vector <int> digits;
void _advance() {
if (++buffPos == buffSZ) {
File.write(buff, buffSZ);
buffPos = 0;
}
}
void printChar(char no) {
buff[buffPos] = no;
_advance();
}
public:
OutParser(const char *FileName) {
File.open(FileName);
digits.resize(11);
buffPos = 0;
}
~OutParser() {
File.write(buff, buffPos);
buffPos = 0;
}
OutParser& operator <<(char ch) {
printChar(ch);
return *this;
}
OutParser& operator <<(int no) {
int idx = 0;
if (no == 0)
digits[++idx] = 0;
while (no) {
digits[++idx] = no % 10;
no /= 10;
}
for (; idx; --idx)
printChar(digits[idx] + '0');
return *this;
}
OutParser& operator <<(long long no) {
int idx = 0;
if (no == 0)
digits[++idx] = 0;
while (no) {
digits[++idx] = no % 10;
no /= 10;
}
for (; idx; --idx)
printChar(digits[idx] + '0');
return *this;
}
};
InParser fin("huffman.in");
OutParser fout("huffman.out");
class HuffmanCode {
private:
static vector <int> defaultVector() {
vector <int> a;
return a;
}
struct QueueItm {
long long freq;
int node;
};
struct HuffmanCodeNode {
int left, right; // left and right children of a node; -1 == NULL
};
queue <QueueItm> LeavesQ;
queue <QueueItm> internalNodesQ;
vector <HuffmanCodeNode> sons; // vertices
vector <int> f; // frequencies
vector <long long> base_10Codes;
vector <int> base_2CodeLengths;
int root; // the root is sons.size() - 1 i.e. the last vertex added to the collection
void buildHuffmanCode();
void DFS(int node);
public:
HuffmanCode(const vector <int> &); // initialize with the frequencies of characters in the file
void computeCodes();
long long CodedLength();
void printBase10Codes();
};
HuffmanCode::HuffmanCode(const vector <int> &frequencies = defaultVector()) {
f = frequencies;
for (int idx = 0; idx < (int)f.size(); ++idx)
LeavesQ.push({ f[idx], idx });
sons.resize(f.size(), { -1, -1 });
buildHuffmanCode();
}
void HuffmanCode::buildHuffmanCode() { // works just because the given numbers are sorted
// complexity O(n)
while (!LeavesQ.empty()) {
long long f1 = 0, f2 = 0;
int node1 = 0, node2 = 0;
// here I just get the nodes with the least frequency from both queues
if (internalNodesQ.empty()) {
f1 = LeavesQ.front().freq;
node1 = LeavesQ.front().node;
LeavesQ.pop();
}
else {
if (LeavesQ.front().freq < internalNodesQ.front().freq) {
f1 = LeavesQ.front().freq;
node1 = LeavesQ.front().node;
LeavesQ.pop();
}
else {
f1 = internalNodesQ.front().freq;
node1 = internalNodesQ.front().node;
internalNodesQ.pop();
}
}
if (internalNodesQ.empty()) {
f2 = LeavesQ.front().freq;
node2 = LeavesQ.front().node;
LeavesQ.pop();
}
else if (LeavesQ.empty()) { // in case LeavesQ got empty from the last set of ifs
f2 = internalNodesQ.front().freq;
node2 = internalNodesQ.front().node;
internalNodesQ.pop();
}
else {
if (LeavesQ.front().freq < internalNodesQ.front().freq) {
f2 = LeavesQ.front().freq;
node2 = LeavesQ.front().node;
LeavesQ.pop();
}
else {
f2 = internalNodesQ.front().freq;
node2 = internalNodesQ.front().node;
internalNodesQ.pop();
}
}
sons.push_back({ node1, node2 });
internalNodesQ.push({ f1 + f2, (int)sons.size() - 1 });
}
// aaand now just continue the greedy for the rest of the internal nodes and we are done
while (internalNodesQ.size() > 1) {
long long f1 = internalNodesQ.front().freq;
int node1 = internalNodesQ.front().node;
internalNodesQ.pop();
long long f2 = internalNodesQ.front().freq;
int node2 = internalNodesQ.front().node;
internalNodesQ.pop();
sons.push_back({ node1, node2 });
internalNodesQ.push({ f1 + f2, (int)sons.size() - 1 });
}
root = (int)sons.size() - 1;
base_10Codes.resize(sons.size(), 0);
base_2CodeLengths.resize(sons.size(), 0);
}
void HuffmanCode::DFS(int node) {
int left = sons[node].left;
int right = sons[node].right;
if (left == -1) // is enough to check for the left son since the tree is full
return;
base_10Codes[left] = 2 * base_10Codes[node];
base_10Codes[right] = 2 * base_10Codes[node] + 1;
base_2CodeLengths[left] = 1 + base_2CodeLengths[node];
base_2CodeLengths[right] = 1 + base_2CodeLengths[node];
DFS(left);
DFS(right);
}
void HuffmanCode::computeCodes() {
DFS(root);
}
long long HuffmanCode::CodedLength() {
long long codedlength = 0;
for (int idx = 0; idx < (int)f.size(); ++idx)
codedlength += 1LL * f[idx] * base_2CodeLengths[idx];
return codedlength;
}
void HuffmanCode::printBase10Codes() {
for (int idx = 0; idx < (int)f.size(); ++idx)
fout << base_2CodeLengths[idx] << ' ' << base_10Codes[idx] << '\n';
}
HuffmanCode hc;
void readData() {
int n;
fin >> n;
vector <int> arr(n);
for (int &itm : arr)
fin >> itm;
hc = arr;
}
int main() {
readData();
hc.computeCodes();
fout << hc.CodedLength() << '\n';
hc.printBase10Codes();
}