Advertisement
omphen

Untitled

Dec 9th, 2023
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 4.92 KB | None | 0 0
  1. // Joel Yang
  2. // CSE 143 DD with Xunmei Liu
  3. // HuffmanTree implements the Huffman algorithm:
  4. // https://en.wikipedia.org/wiki/Huffman_coding
  5. // It can build trees in two different ways, one being
  6. // through a frequency array and one being through
  7. // a preordered, standard file. It can also do the opposite;
  8. // writing trees to a standard file. It can also decode
  9. // files given an encoded file.
  10.  
  11. package Homework8;
  12.  
  13. import java.io.*;
  14. import java.util.*;
  15.  
  16. // creates a "Huffman tree", using the algorithm as described above.
  17. public class HuffmanTree {
  18.     public HuffmanNode overallRoot;
  19.     private Queue<HuffmanNode> freqQueue;
  20.  
  21.     // constructs a "Huffman tree" given an array of frequencies
  22.     public HuffmanTree(int[] count) {
  23.         freqQueue = new PriorityQueue<>();
  24.         fillQueue(count);
  25.         buildTree();
  26.         overallRoot = freqQueue.remove();
  27.     }
  28.  
  29.     // fills queue with "Huffman nodes" given our frequencies for each character.
  30.     // includes pseudo end-of-file character, whose 'character' is 1 + the highest
  31.     // character passed through the frequency array, and whose 'frequency' is, logically,
  32.     // 1.
  33.     private void fillQueue(int[] count) {
  34.         for (int i = 0; i < count.length; i++) {
  35.             if (count[i] > 0) {
  36.                 freqQueue.add(new HuffmanNode(i, count[i]));
  37.             }
  38.         }
  39.         freqQueue.add(new HuffmanNode(count.length, 1));
  40.     }
  41.  
  42.     // recursively creates our final "Huffman tree"
  43.     private void buildTree() {
  44.         if (freqQueue.size() > 1) {
  45.             HuffmanNode front1 = freqQueue.remove();
  46.             HuffmanNode front2 = freqQueue.remove();
  47.             HuffmanNode root = new HuffmanNode(front1.freq + front2.freq);
  48.             root.left = front1;
  49.             root.right = front2;
  50.             freqQueue.add(root);
  51.             buildTree();
  52.         }
  53.     }
  54.  
  55.     // writes tree to an output file / stream in standard (preorder) format
  56.     public void write(PrintStream output) {
  57.         write(output, overallRoot, "");
  58.     }
  59.  
  60.     // loosely based on hw7
  61.     private void write(PrintStream output, HuffmanNode root, String freqString) {
  62.         if (isCharacter(root)) {
  63.             output.println(root.character);
  64.             output.println(freqString);
  65.         } else {
  66.             write(output, root.left, freqString + "0");
  67.             write(output, root.right, freqString + "1");
  68.         }
  69.     }
  70.  
  71.     // alternate constructor: reconstructs a "Huffman tree" from a file,
  72.     // assuming input is stored in standard (preorder) format
  73.     public HuffmanTree(Scanner input) {
  74.         overallRoot = loadRead(input);
  75.     }
  76.  
  77.     // parses through input
  78.     private HuffmanNode loadRead(Scanner input) {
  79.         HuffmanNode current = new HuffmanNode(-1);
  80.         while (input.hasNextLine()) {
  81.             int n = Integer.parseInt(input.nextLine());
  82.             String code = input.nextLine();
  83.             current = read(current, n, code);
  84.         }
  85.         return current;
  86.     }
  87.  
  88.     // via loadRead; builds one pathway to one leaf from our original root
  89.     private HuffmanNode read(HuffmanNode root, int n, String code) {
  90.         if (root == null) {
  91.             root = new HuffmanNode(-1);
  92.         }
  93.         if (code.isEmpty()) {
  94.             root.character = n;
  95.         } else {
  96.             if (code.charAt(0) == '0') {
  97.                 root.left = read(root.left, n, code.substring(1));
  98.             } else {
  99.                 root.right = read(root.right, n, code.substring(1));
  100.             }
  101.         }
  102.         return root;
  103.     }
  104.  
  105.     // reads individual bits from the input stream, writing them to the output.
  106.     // stops upon encountering the pseudo end-of-file character mentioned below.
  107.     // said character is not written to the output. assumes that the input is encoded
  108.     // legally for this particular program.
  109.     public void decode(BitInputStream input, PrintStream output, int eof) {
  110.         HuffmanNode current = new HuffmanNode(-1);
  111.         boolean reachedEndOfFile = false;
  112.         while (!reachedEndOfFile) {
  113.             current = overallRoot;
  114.             int character = getCharacter(current, input);
  115.             if (character == eof) {
  116.                 reachedEndOfFile = true;
  117.             } else {
  118.                 output.write(character);
  119.             }
  120.         }
  121.     }
  122.  
  123.     // recursively grabs individual characters using our tree and a bit stream
  124.     private int getCharacter(HuffmanNode root, BitInputStream input) {
  125.         if (isCharacter(root)) {
  126.             return root.character;
  127.         } else {
  128.             if (input.readBit() == 0) {
  129.                 return getCharacter(root.left, input);
  130.             } else {
  131.                 return getCharacter(root.right, input);
  132.             }
  133.         }
  134.     }
  135.  
  136.     // returns true if node has a valid character, aka is a leaf
  137.     private boolean isCharacter(HuffmanNode root) {
  138.         return root.left == null && root.right == null;
  139.     }
  140. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement