Cod sursa(job #2612049)

Utilizator DawlauAndrei Blahovici Dawlau Data 8 mai 2020 02:50:22
Problema Coduri Huffman Scor 65
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.55 kb
#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 HeapKey {

		int freq, idx;

		bool operator < (const HeapKey &other) const {

			if (freq == other.freq)
				return idx > other.idx;
			return freq > other.freq;
		}
	};

	struct HuffmanCodeNode {

		int left, right; // left and right children of a node; -1 == NULL
	};

	priority_queue < HeapKey, vector < HeapKey > > Heap; // minHeap freq + idx
	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)
		Heap.push({ f[idx], idx });

	sons.resize(f.size(), {-1, -1});
	//sons.reserve(2 * f.size() - 1);

	buildHuffmanCode();
}

void HuffmanCode::buildHuffmanCode() {

	while (Heap.size() > 1) {

		int f1 = Heap.top().freq;
		int idx1 = Heap.top().idx;
		Heap.pop();

		int f2 = Heap.top().freq;
		int idx2 = Heap.top().idx;
		Heap.pop();

		sons.push_back({idx1, idx2});
		Heap.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();
}