├── .gitignore ├── LICENSE ├── fib.rs ├── main.rs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | fib -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Alexey Kutepov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /fib.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | fn fib(n: usize) -> usize { 3 | if n < 2 { 4 | n 5 | } else { 6 | fib(n - 1) + fib(n - 2) 7 | } 8 | } 9 | 10 | #[derive(Debug)] 11 | enum Action { 12 | Call(T), 13 | Handle(U), 14 | } 15 | 16 | fn fib_nonrec(n: usize) -> usize { 17 | let mut arg_stack = Vec::>::new(); 18 | let mut ret_stack = Vec::::new(); 19 | 20 | use Action::*; 21 | arg_stack.push(Call(n)); 22 | while let Some(action) = arg_stack.pop() { 23 | println!("action = {:?}", &action); 24 | match action { 25 | Call(n) => if n < 2 { 26 | ret_stack.push(n) 27 | } else { 28 | arg_stack.push(Handle(())); 29 | arg_stack.push(Call(n - 2)); 30 | arg_stack.push(Call(n - 1)); 31 | }, 32 | 33 | Handle(()) => { 34 | let a = ret_stack.pop().unwrap(); 35 | let b = ret_stack.pop().unwrap(); 36 | ret_stack.push(a + b); 37 | }, 38 | } 39 | println!("arg_stack = {:?}", &arg_stack); 40 | println!("ret_stack = {:?}", &ret_stack); 41 | println!("------------------------------") 42 | } 43 | 44 | ret_stack.pop().unwrap() 45 | } 46 | 47 | fn main() { 48 | fib_nonrec(3); 49 | } 50 | -------------------------------------------------------------------------------- /main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Debug}; 2 | 3 | type NodeRef = Option>>; 4 | 5 | #[derive(Debug, Default, Clone)] 6 | struct Node { 7 | value: T, 8 | left: NodeRef, 9 | right: NodeRef, 10 | } 11 | 12 | #[derive(Debug)] 13 | enum Action { 14 | Call(T), 15 | Handle(U) 16 | } 17 | 18 | fn generate_tree(level: usize) -> NodeRef { 19 | let mut counter = 1; 20 | let mut arg_stack = Vec::>::new(); 21 | let mut ret_stack = Vec::>::new(); 22 | 23 | use Action::*; 24 | arg_stack.push(Call(level)); 25 | while let Some(action) = arg_stack.pop() { 26 | match action { 27 | Call(level) => if level > 0 { 28 | arg_stack.push(Handle(counter)); 29 | counter += 1; 30 | arg_stack.push(Call(level - 1)); 31 | arg_stack.push(Call(level - 1)); 32 | } else { 33 | ret_stack.push(None); 34 | }, 35 | Handle(value) => { 36 | let left = ret_stack.pop().unwrap(); 37 | let right = ret_stack.pop().unwrap(); 38 | ret_stack.push(Some(Box::new(Node{value, left, right}))); 39 | }, 40 | } 41 | } 42 | 43 | ret_stack.pop().unwrap() 44 | } 45 | 46 | fn print_tree(root: &NodeRef) { 47 | let mut stack = Vec::, usize), (&T, usize)>>::new(); 48 | use Action::*; 49 | stack.push(Call((root, 0))); 50 | while let Some(action) = stack.pop() { 51 | match action { 52 | Call((root, level)) => if let Some(node) = root { 53 | stack.push(Call((&node.left, level + 1))); 54 | stack.push(Handle((&node.value, level))); 55 | stack.push(Call((&node.right, level + 1))); 56 | }, 57 | Handle((value, level)) => { 58 | for _ in 0..level { 59 | print!(" ") 60 | } 61 | println!("{}", value); 62 | } 63 | } 64 | } 65 | } 66 | 67 | fn invert_tree(root: &NodeRef) -> NodeRef { 68 | let mut arg_stack = Vec::, &T>>::new(); 69 | let mut ret_stack = Vec::>::new(); 70 | 71 | use Action::*; 72 | arg_stack.push(Call(root)); 73 | while let Some(action) = arg_stack.pop() { 74 | match action { 75 | Call(root) => if let Some(node) = root { 76 | arg_stack.push(Handle(&node.value)); 77 | arg_stack.push(Call(&node.right)); 78 | arg_stack.push(Call(&node.left)); 79 | } else { 80 | ret_stack.push(None) 81 | }, 82 | Handle(value) => { 83 | let left = ret_stack.pop().unwrap(); 84 | let right = ret_stack.pop().unwrap(); 85 | ret_stack.push(Some(Box::new(Node{value: value.clone(), left, right}))); 86 | }, 87 | } 88 | } 89 | 90 | ret_stack.pop().unwrap() 91 | } 92 | 93 | fn main() { 94 | let tree = generate_tree(3); 95 | println!("Original Tree:"); 96 | print_tree(&tree); 97 | println!("Inverted Tree:"); 98 | print_tree(&invert_tree(&tree)); 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Non-Recursive Inverting of Binary Tree in Rust 2 | 3 | The idea is to implement the classical [Inverting of Binary Tree](https://twitter.com/mxcl/status/608682016205344768?lang=en) but without using recursion. 4 | 5 | ## Quick Start 6 | 7 | ```console 8 | $ rustc main.rs 9 | $ ./main 10 | ``` 11 | 12 | ## Main Idea 13 | 14 | The Main Idea is to basically simulate the recursion by managing two stacks: one for the arguments (`arg_stack`) and one for the return values (`ret_stack`). The `arg_stack` contains a sequence of two kinds of actions: 15 | 16 | ```rust 17 | #[derive(Debug)] 18 | enum Action { 19 | Call(T), 20 | Handle(U), 21 | } 22 | ``` 23 | 24 | `Call` simulates the recursive function call with the given arguments `T`, `Handle` allows to postpone the handling of the return values on `ret_stack` to achieve a specific order of execution that is usually achieved by using recursive functions. 25 | 26 | This forms a general purpose framework that enables us to convert any (I believe so, can't formally prove it) recursive function into a non-recursive one. 27 | 28 | Let's take a look at a simple recursive function that calculates `n`-th Fibonacci number: 29 | 30 | ```rust 31 | fn fib(n: usize) -> usize { 32 | if n < 2 { 33 | n 34 | } else { 35 | fib(n - 1) + fib(n - 2) 36 | } 37 | } 38 | ``` 39 | 40 | This is how you would implement such function in a non-recursive fashion using the aforementioned framework: 41 | 42 | ```rust 43 | fn fib_nonrec(n: usize) -> usize { 44 | let mut arg_stack = Vec::>::new(); 45 | let mut ret_stack = Vec::::new(); 46 | 47 | use Action::*; 48 | arg_stack.push(Call(n)); 49 | while let Some(action) = arg_stack.pop() { 50 | println!("action = {:?}", &action); 51 | match action { 52 | Call(n) => if n < 2 { 53 | ret_stack.push(n) 54 | } else { 55 | arg_stack.push(Handle(())); 56 | arg_stack.push(Call(n - 2)); 57 | arg_stack.push(Call(n - 1)); 58 | }, 59 | 60 | Handle(()) => { 61 | let a = ret_stack.pop().unwrap(); 62 | let b = ret_stack.pop().unwrap(); 63 | ret_stack.push(a + b); 64 | }, 65 | } 66 | println!("arg_stack = {:?}", &arg_stack); 67 | println!("ret_stack = {:?}", &ret_stack); 68 | println!("------------------------------") 69 | } 70 | 71 | ret_stack.pop().unwrap() 72 | } 73 | ``` 74 | 75 | Calling `fib_nonrec(3)` generates the following log: 76 | 77 | ```console 78 | action = Call(3) 79 | arg_stack = [Handle(()), Call(1), Call(2)] 80 | ret_stack = [] 81 | ------------------------------ 82 | action = Call(2) 83 | arg_stack = [Handle(()), Call(1), Handle(()), Call(0), Call(1)] 84 | ret_stack = [] 85 | ------------------------------ 86 | action = Call(1) 87 | arg_stack = [Handle(()), Call(1), Handle(()), Call(0)] 88 | ret_stack = [1] 89 | ------------------------------ 90 | action = Call(0) 91 | arg_stack = [Handle(()), Call(1), Handle(())] 92 | ret_stack = [1, 0] 93 | ------------------------------ 94 | action = Handle(()) 95 | arg_stack = [Handle(()), Call(1)] 96 | ret_stack = [1] 97 | ------------------------------ 98 | action = Call(1) 99 | arg_stack = [Handle(())] 100 | ret_stack = [1, 1] 101 | ------------------------------ 102 | action = Handle(()) 103 | arg_stack = [] 104 | ret_stack = [2] 105 | ------------------------------ 106 | ``` 107 | 108 | The top of the stacks is on the right. 109 | 110 | Notice how the `arg_stack` grows until it exhausts `n` and shrinks back computing the final result into the `ret_stack`. This is basically the simulation of the recursive process. 111 | 112 | The resulting code is admittedly bigger, less readable and more difficult to extend, so I do not generally recommend to develop in this style. This entire example was created as a coding exercise. Although this approach might be useful for doing very deep recursion to prevent stack overflows, since [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html) can extend for as long as there is available memory and the call stack is usually limited. 113 | --------------------------------------------------------------------------------