import java.util.*;
import java.io.*;
public class HuffmanCode {
private HuffmanNode head;
public HuffmanCode(int[] frequencies){
Queue<HuffmanNode> Pqueue = new PriorityQueue<HuffmanNode>();
for (int i = 0; i < frequencies.length; i++){
if (frequencies[i] > 0){
Pqueue.add(new HuffmanNode(i, frequencies[i]));
}
}
while(Pqueue.size() > 1){
//HuffmanNode firstRemove = Pqueue.peek();
HuffmanNode firstRemove = Pqueue.remove();
// HuffmanNode secondRemove = Pqueue.peek();
HuffmanNode secondRemove = Pqueue.remove();
Pqueue.add(new HuffmanNode(-1, firstRemove.frequency + secondRemove.frequency , firstRemove, secondRemove));
}
head = Pqueue.remove();
}
public HuffmanCode(Scanner input){
while (input.hasNextLine()){
String data = input.nextLine();
String encoding = input.nextLine();
head = maketree(head, Integer.parseInt(data), encoding);
}
}
private HuffmanNode maketree(HuffmanNode current, int data, String encoding){
if (encoding.length() == 0){
return new HuffmanNode(data, 0, null, null);
}
else{
if (current == null){
current = new HuffmanNode(-1, 0, null, null);
}
if (encoding.charAt(0) == '0'){
current.left = maketree(current.left, data, encoding.substring(1));
}
else{
current.right = maketree(current.right, data, encoding.substring(1));
}
return current;
}
}
public void save(PrintStream output){
String continuing = "";
traverseTree(output, head, continuing);
}
//Note: Let the user know the tree-reading order in the comment.
private void traverseTree(PrintStream output, HuffmanNode curr, String continuing){
if (curr != null){
if (curr.left == null && curr.right == null){
output.println(curr.getASCII());
output.println(continuing);
}
else{
if (curr.left != null){
traverseTree(output, curr.left, continuing + "0");
}
if (curr.right != null){
traverseTree(output, curr.right, continuing + "1");
}
}
}
}
public void translate(BitInputStream input, PrintStream output){
//public int nextBit()
while(input.hasNextBit()){
translate(input, output, head);
}
}
private void translate (BitInputStream input, PrintStream output, HuffmanNode curr){
if (curr.left == null && curr.right == null){
output.write((char)curr.getASCII());
}
else{
int nextBit = input.nextBit();
if (nextBit == 0){
translate(input, output, curr.left);
}
else{
translate(input, output, curr.right);
}
}
}
public static class HuffmanNode implements Comparable<HuffmanNode>{
private int ASCIINo;
private int frequency;
private HuffmanNode left;
private HuffmanNode right;
public HuffmanNode(int ASCIINo, int frequency){
this(ASCIINo, frequency, null, null);
}
public HuffmanNode(int ASCIINo, int frequency, HuffmanNode left, HuffmanNode right){
this.ASCIINo = ASCIINo;
this.frequency = frequency;
this.left = left;
this.right = right;
}
public int getASCII(){
return this.ASCIINo;
}
@Override
public int compareTo(HuffmanNode other){
return this.frequency - other.frequency;
}
}
}