Skip to content

Instantly share code, notes, and snippets.

@jlgerber
Created May 5, 2018 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlgerber/fdbd8133c1dd6217995d7aca629a50b3 to your computer and use it in GitHub Desktop.
Save jlgerber/fdbd8133c1dd6217995d7aca629a50b3 to your computer and use it in GitHub Desktop.
rust stack vs recursion
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