Created
May 5, 2018 17:11
-
-
Save jlgerber/fdbd8133c1dd6217995d7aca629a50b3 to your computer and use it in GitHub Desktop.
rust stack vs recursion
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
static STUFF: &'static [&'static str] = &[ | |
"foo", | |
"bar", | |
"bla", | |
"crar", | |
"mala", | |
"court", | |
"dupla", | |
"fooobas", | |
"lalalala", | |
"hubahuba", | |
"vroom", | |
"capich", | |
"calor", | |
"moohaha", | |
"redundant", | |
"calfo", | |
"dismar", | |
"rafgrub", | |
"upstaq", | |
]; | |
#[derive(Debug)] | |
/// Stuff holds datum and a vec of | |
/// boxed children. | |
pub struct Stuff { | |
pub datum: String, | |
pub children: Vec<Box<Stuff>>, | |
} | |
impl Stuff { | |
/// Given an index into STUFF as a starting point, we look up | |
/// an appropriate datum from STUFF at the provided index modulo | |
/// the size of STUFF to avoid overflowing it. We then return | |
/// a new Stuff instance with an empty children vec | |
fn new(idx: usize) -> Stuff { | |
let idx: usize = idx % (STUFF.len()); | |
Stuff { | |
datum: String::from(STUFF[idx]), | |
children: Vec::new(), | |
} | |
} | |
/// Given an index into STUFF to look up the datum, we add a child | |
/// to Self, by Boxing a call to Suff::new and pushing the result | |
/// into self.children | |
fn add_child(&mut self, idx: usize) { | |
self.children.push(Box::new(Stuff::new(idx))); | |
} | |
} | |
/// Given a reference to stuff, go ahead and | |
/// print it and its children via recursion. | |
pub fn printrec(node: &Box<Stuff>, depth: usize) { | |
println!("{}{}", " ".repeat(depth), node.datum); | |
for child in &node.children { | |
printrec(child, depth + 1); | |
} | |
} | |
/// Given a reference to a Boxed Stuff instance, we print | |
/// out its datum, as well as that of all of its descendents, | |
/// without using recusion. Instead, we use a stack.e | |
pub fn printstack(node: &Box<Stuff>) { | |
let mut stack: Vec<(&Box<Stuff>, usize)> = Vec::new(); | |
stack.push((node, 0)); | |
while stack.len() > 0 { | |
let val = stack.pop().unwrap(); | |
println!("{}{}", " ".repeat(val.1), val.0.datum); | |
// This was the original code. However, I decided that a more | |
// idiomatic approach would be to use an iterator and | |
// a couple of iterator adapters. | |
// | |
// # Original | |
// ``` | |
// for c in val.0.children.iter().rev() { | |
// stack.push((c,val.1 + 1)); | |
// } | |
// ``` | |
val.0 | |
.children | |
.iter() | |
.rev() | |
.map(|ref x| stack.push((&x, val.1 + 1))) | |
.collect::<()>(); | |
} | |
} | |
fn build_root() -> Stuff { | |
let mut root = Stuff::new(0); | |
for x in 1..10 { | |
root.add_child(x); | |
} | |
for c in 0..root.children.len() { | |
for x in 1..5 { | |
root.children[c].add_child(x + c * 5); | |
} | |
} | |
root | |
} | |
fn main() { | |
let root = build_root(); | |
let root = Box::new(root); | |
println!("\n{}RECURSION{}\n", "=".repeat(5), "=".repeat(5)); | |
printrec(&root, 0); | |
println!("\n\n{}STACK{}\n", "=".repeat(5), "=".repeat(5)); | |
printstack(&root); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment