Skip to content

Instantly share code, notes, and snippets.

@nsmaciej
Last active February 17, 2017 05:57
Show Gist options
  • Save nsmaciej/f93cee3f04fbd908d154e4a5fe4f4bf2 to your computer and use it in GitHub Desktop.
Save nsmaciej/f93cee3f04fbd908d154e4a5fe4f4bf2 to your computer and use it in GitHub Desktop.
Huffman encoding assignment
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