Last active
June 11, 2017 17:06
-
-
Save sireliah/b754748eda205c8b790753cb5d109396 to your computer and use it in GitHub Desktop.
My attempt to implement Huffman coding algorithm in Rust
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
| #![feature(box_patterns, box_syntax)] | |
| use std::collections::HashMap; | |
| /// "z" is our lifetime parameter. | |
| #[derive(Debug)] | |
| struct Node<'z> { | |
| symbol: &'z str, | |
| prob: f32, | |
| /// Box reallocates the node from stack to heap. Otherwise, the compiler will complain that "recursive type `Node` has infinite size" | |
| left: Option<Box<Node<'z>>>, | |
| right: Option<Box<Node<'z>>>, | |
| } | |
| impl<'z> Node<'z> { | |
| // fn new_node(symbol: &'z str, first: Node<'z>, second: Node<'z>) -> Node<'z> { | |
| // Node { | |
| // symbol: symbol, | |
| // prob: first.prob + second.prob, | |
| // left: Some(Box::new(first)), | |
| // right: Some(Box::new(second)), | |
| // } | |
| // } | |
| fn build_dictionary(&self, result_list: Vec<(&Node, Vec<i32>)>) -> HashMap<String, Vec<i32>> { | |
| /// TODO: create this using map() | |
| let mut dictionary = HashMap::new(); | |
| for tuple in &result_list { | |
| if tuple.0.symbol != "*" { | |
| //println!("{}, {:?}", tuple.0.symbol, tuple.1); | |
| let codes = tuple.1.clone(); | |
| let symbol = tuple.0.symbol.to_string().clone(); | |
| dictionary.insert(symbol, codes); | |
| } | |
| } | |
| return dictionary; | |
| } | |
| fn generate_codes(&self) -> Vec<(&Node, Vec<i32>)> { | |
| let mut stack = Vec::<(&Node, Vec<i32>)>::new(); | |
| let mut result = Vec::<(&Node, Vec<i32>)>::new(); | |
| // let mut code = "".as_string(); | |
| stack.push((self, vec![])); | |
| while !stack.is_empty() { | |
| let (node, codes) = stack.pop().unwrap(); | |
| let copied_node = node.clone(); | |
| let copied_codes = codes.clone(); | |
| result.push((copied_node, copied_codes)); | |
| //println!("{}, {}", node.symbol, node.prob); | |
| //println!("{:?}", codes); | |
| if let Some(box ref nod) = node.right { | |
| let mut new_codes = codes.clone(); | |
| new_codes.push(1); | |
| stack.push((nod, new_codes)); | |
| } | |
| if let Some(box ref nod) = node.left { | |
| let mut new_codes = codes.clone(); | |
| new_codes.push(0); | |
| stack.push((nod, new_codes)); | |
| } | |
| } | |
| return result; | |
| } | |
| } | |
| fn get_two_lowest(nodes: &mut Vec<Node>) -> bool { | |
| /// First sort by probability. | |
| nodes.sort_by(|a, b| b.prob.partial_cmp(&a.prob).unwrap()); | |
| let first = match nodes.pop() { | |
| Some(i) => i, | |
| None => return true, | |
| }; | |
| let second: Node = match nodes.pop() { | |
| Some(i) => i, | |
| None => return true, | |
| }; | |
| //let new_node = Node::new_node("*", first, second); | |
| /// Create new node with lowest nodes as children. | |
| let new_node = Node { | |
| symbol: "*", | |
| prob: first.prob + second.prob, | |
| left: Some(Box::new(first)), | |
| right: Some(Box::new(second)), | |
| }; | |
| nodes.push(new_node); | |
| return false; | |
| } | |
| // fn traverse(node: Node) { | |
| // let mut stack: Vec<&Node> = Vec::new(); | |
| // let mut res: Vec<&Node> = Vec::new(); | |
| // match node.left { | |
| // Some(left) => encode(left, "left"), | |
| // None => println!("nothin' on left found"), | |
| // } | |
| // match node.right { | |
| // Some(right) => encode(right, "right"), | |
| // None => println!("nothin' on right found"), | |
| // } | |
| //} | |
| fn main() { | |
| //let mut key_map = HashMap::new(); | |
| let mut nodes = vec![ | |
| Node {symbol: "A", prob: 0.4, left: None, right: None}, | |
| Node {symbol: "B", prob: 0.3, left: None, right: None}, | |
| Node {symbol: "C", prob: 0.2, left: None, right: None}, | |
| Node {symbol: "D", prob: 0.1, left: None, right: None}, | |
| ]; | |
| //let mut stop = false; | |
| while nodes.len() > 1 { | |
| get_two_lowest(&mut nodes); | |
| } | |
| println!("Number of nodes: {}", nodes.len()); | |
| for node in &nodes { | |
| println!("Iterating nodes: symbol: {}, prob: {}", node.symbol, node.prob); | |
| } | |
| let root: Node = nodes.pop().unwrap(); | |
| let result = root.generate_codes(); | |
| let dictionary = root.build_dictionary(result); | |
| println!("{:?}", dictionary); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment