Last active
February 17, 2017 05:57
-
-
Save nsmaciej/f93cee3f04fbd908d154e4a5fe4f4bf2 to your computer and use it in GitHub Desktop.
Huffman encoding assignment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::io; | |
| use std::cmp::max; | |
| use std::cmp::{Ordering, PartialOrd}; | |
| use std::cmp::Ordering::*; | |
| use std::collections::HashMap; | |
| use std::collections::BinaryHeap; | |
| #[derive(Debug)] | |
| enum Node { Leaf(char), Branch(Box<Node>, Box<Node>) } | |
| #[derive(Debug)] | |
| struct Tree { root: Node, freq: i32 } | |
| impl PartialOrd for Tree { | |
| fn partial_cmp(&self, other: &Tree) -> Option<Ordering> { | |
| Some(self.cmp(&other)) | |
| } | |
| } | |
| impl Ord for Tree { | |
| fn cmp(&self, other: &Tree) -> Ordering { | |
| match self.freq.cmp(&other.freq) { | |
| Less => Greater, | |
| Equal => Equal, | |
| Greater => Less | |
| } | |
| } | |
| } | |
| impl PartialEq for Tree { | |
| fn eq(&self, other: &Tree) -> bool { | |
| self.freq == other.freq | |
| } | |
| } | |
| impl Eq for Tree {} | |
| fn find_code(node: &Node, c: char) -> Option<String> { | |
| match *node { | |
| Node::Leaf(x) if x == c => Some(String::new()), | |
| Node::Branch(ref left, ref right) => { | |
| find_code(&left, c) | |
| .map(|p| "0".to_string() + &p) | |
| .or_else(|| find_code(&right, c).map(|p| "1".to_string() + &p)) | |
| } | |
| _ => None, | |
| } | |
| } | |
| fn newline(i: usize) { | |
| if i % 8 == 0 && i > 0 { | |
| println!(); | |
| } | |
| } | |
| fn main() { | |
| let mut line = String::new(); | |
| let mut heap = BinaryHeap::new(); | |
| let mut count: HashMap<char, i32> = HashMap::new(); | |
| let (mut before, mut after) = (0, 0); | |
| io::stdin().read_line(&mut line).expect("couldn't read stdin"); | |
| for c in line.trim_right().chars() { | |
| *count.entry(c).or_insert(0) += 1; | |
| } | |
| for (i, c) in line.trim_right().chars().enumerate() { | |
| newline(i); | |
| before += max(7, format!("{:b}", c as usize).len()); | |
| print!("{:07b} ", c as usize); | |
| } | |
| print!("\n\n"); | |
| for (k, v) in count { | |
| println!("'{}' appeared {} {}", k, v, if v == 1 { "time" } else { "times" }); | |
| heap.push(Tree { root: Node::Leaf(k), freq: v }); | |
| } | |
| print!("\n"); | |
| while heap.len() > 1 { | |
| let (left, right) = (heap.pop().unwrap(), heap.pop().unwrap()); | |
| heap.push(Tree { | |
| root: Node::Branch(Box::new(left.root), Box::new(right.root)), | |
| freq: left.freq + right.freq, | |
| }) | |
| } | |
| let tree = heap.pop().unwrap().root; | |
| for (i, c) in line.trim_right().chars().enumerate() { | |
| newline(i); | |
| let mut code = find_code(&tree, c).unwrap(); | |
| if code.len() == 0 { | |
| code = "0".to_string(); | |
| } | |
| after += code.len(); | |
| print!("{:<7} ", code); | |
| } | |
| print!("\n\n"); | |
| println!("Compressed size is {} bits / {} bits = {:.0} %", after, before, 100. * after as f32 / before as f32); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment