Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4f5ffb1

Browse files
Added the tree!() macro
It gives the user more control in how they create their TreeNode struct.
1 parent 20b7569 commit 4f5ffb1

File tree

4 files changed

+275
-32
lines changed

4 files changed

+275
-32
lines changed

‎Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ serde = { version = "1.0.201", features = ["derive"], optional = true }
1818
cargo-make = "0.37.12"
1919

2020
[features]
21+
# Internal
22+
tree_macros_internals = []
23+
24+
# Other libraries
2125
serde = ["dep:serde"]

‎src/macros/helper_functions.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use crate::utils::TreeNode;
2+
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
3+
4+
/// Boilerplate...
5+
#[cfg(feature = "tree_macros_internals")]
6+
#[doc(hidden)]
7+
fn rc_cell_tree_node(val: i32) -> Rc<RefCell<TreeNode>> {
8+
Rc::new(RefCell::new(TreeNode::new(val)))
9+
}
10+
11+
/// This function can be inferred from the `tree!()` macro which works and is documented based on
12+
/// it.
13+
#[cfg(feature = "tree_macros_internals")]
14+
#[doc(hidden)]
15+
pub fn _build_tree(levels: &[Vec<Option<i32>>]) -> Option<Rc<RefCell<TreeNode>>> {
16+
if levels.is_empty() || levels[0].is_empty() || levels[0][0].is_none() {
17+
return None;
18+
}
19+
20+
let root = rc_cell_tree_node(levels[0][0].unwrap());
21+
22+
let mut queue = VecDeque::new();
23+
queue.push_back(Rc::clone(&root));
24+
25+
for (i, _) in levels.iter().enumerate().skip(1) {
26+
let mut next_level_nodes = VecDeque::new();
27+
let mut curr_item = 0;
28+
29+
for parent in &queue {
30+
if let Some(Some(left_val)) = levels[i].get(curr_item) {
31+
let left_child = rc_cell_tree_node(*left_val);
32+
parent.borrow_mut().left = Some(Rc::clone(&left_child));
33+
next_level_nodes.push_back(left_child);
34+
}
35+
curr_item += 1;
36+
37+
if let Some(Some(right_val)) = levels[i].get(curr_item) {
38+
let right_child = rc_cell_tree_node(*right_val);
39+
parent.borrow_mut().right = Some(Rc::clone(&right_child));
40+
next_level_nodes.push_back(right_child);
41+
}
42+
curr_item += 1;
43+
}
44+
45+
queue = next_level_nodes;
46+
}
47+
48+
Some(root)
49+
}

‎src/macros/mod.rs

Lines changed: 221 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/// Iternal macro helper functions.
2+
#[cfg(feature = "tree_macros_internals")]
3+
#[doc(hidden)]
4+
pub mod helper_functions;
5+
16
///////////////////////////////////////////////////////////////////////////////////////////////////
27
// List Node macros
38
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -6,6 +11,17 @@
611
///
712
/// A macro to reduce the boilerplate in generating a full ListNode.
813
///
14+
/// ## Match arms
15+
///
16+
/// Arm 1:
17+
/// - Takes the value as an argument.
18+
/// - Equivalent of doing `ListNode::new()`.
19+
///
20+
/// Arm 2:
21+
/// - Takes the value as an argument.
22+
/// - Also takes a sequence of left and right node values at the same time (which means they're
23+
/// symmetric) as an argument (and builds the `ListNode` struct with them).
24+
///
925
/// ## Example
1026
///
1127
/// This code:
@@ -52,38 +68,194 @@ macro_rules! list_node {
5268
// Tree Node macros
5369
///////////////////////////////////////////////////////////////////////////////////////////////////
5470

55-
/// TODO:
56-
/// You can generate TreeNodes manually by utilizing tuples. The first value is a single value and
57-
/// everything else is a tuple of `(Option<i32>, Option<i32>)`
58-
// #[macro_export]
59-
#[allow(unused_macros)]
71+
/// ## Description
72+
///
73+
/// You can generate TreeNodes manually by utilizing a `[Vec<Option<i32>]` data structure.
74+
///
75+
/// **IMPORTANT:** Whenever you have more Nodes and there's a None node above - It's up to you to
76+
/// make sure that the nodes are matched correctly. Whenever there's a `None` value at a level
77+
/// that's not the last one then the next level will ignore every impossible value. This means that
78+
/// if you want this tree:
79+
///
80+
/// ```markdown
81+
/// Some(100) // Root Node
82+
/// / \
83+
/// None Some(21) // Left and Right nodes respectively
84+
/// / \
85+
/// None None
86+
/// ```
87+
///
88+
/// You need to call the macro like this:
89+
///
90+
/// ```rust
91+
/// use std::{rc::Rc, cell::RefCell};
92+
/// use leetcode_trees_rs::utils::{tree, TreeNode};
93+
///
94+
/// let tree = tree!(
95+
/// &[
96+
/// vec![Some(100)],
97+
/// vec![None, Some(21)],
98+
/// vec![Some(11), None], // **DON'T** use 4 `Option` values! The first two are inferred!
99+
/// ]
100+
/// );
101+
///
102+
/// assert_eq!(
103+
/// tree,
104+
/// Some(Rc::new(RefCell::new(TreeNode {
105+
/// val: 100,
106+
/// left: None,
107+
/// right: Some(Rc::new(RefCell::new(TreeNode {
108+
/// val: 21,
109+
/// left: Some(Rc::new(RefCell::new(TreeNode::new(11)))),
110+
/// right: None
111+
/// })))
112+
/// })))
113+
/// );
114+
/// ```
115+
///
116+
/// Another important note: If the `None` value is a the end of a vec like this:
117+
///
118+
/// ```rust
119+
/// use std::{rc::Rc, cell::RefCell};
120+
/// use leetcode_trees_rs::utils::{tree, TreeNode};
121+
///
122+
/// let tree = tree!(
123+
/// &[
124+
/// vec![Some(100)],
125+
/// vec![Some(21), None], // ! You need to have that trialing None !
126+
/// vec![Some(11)], // Otherwise this `11` will get written to root->right rather
127+
/// // than of root->left->left.
128+
/// ]
129+
/// );
130+
///
131+
/// assert_eq!(
132+
/// tree,
133+
/// Some(Rc::new(RefCell::new(TreeNode {
134+
/// val: 100,
135+
/// left: Some(Rc::new(RefCell::new(TreeNode {
136+
/// val: 21,
137+
/// left: Some(Rc::new(RefCell::new(TreeNode::new(11)))),
138+
/// right: None
139+
/// }))),
140+
/// right: None
141+
/// })))
142+
/// );
143+
/// ```
144+
///
145+
/// ## Match arms
146+
///
147+
/// Arm 1:
148+
/// - Takes the `[Vec<Option<i32>>]` data type which contains the `TreeNode` values based on the
149+
/// description for this macro.
150+
///
151+
///
152+
/// ## Additional examples
153+
///
154+
/// Making a tree only towards the left side:
155+
///
156+
/// ```rust
157+
/// use std::{cell::RefCell, rc::Rc};
158+
/// use leetcode_trees_rs::utils::{tree, symmetric_tree, TreeNode};
159+
///
160+
/// let node_left_sided = TreeNode {
161+
/// val: 1,
162+
/// left: Some(Rc::new(RefCell::new(TreeNode {
163+
/// val: 2,
164+
/// left: Some(Rc::new(RefCell::new(TreeNode::new(5)))),
165+
/// right: Some(Rc::new(RefCell::new(TreeNode::new(6)))),
166+
/// }))),
167+
/// right: None,
168+
/// };
169+
/// assert_eq!(
170+
/// Rc::new(RefCell::new(node_left_sided)),
171+
/// tree!(
172+
/// &[
173+
/// vec![Some(1)],
174+
/// vec![Some(2), None], // (!) You need to specify any trailing `None` values.
175+
/// vec![Some(5), Some(6), /* None, None */],
176+
/// ]
177+
/// ).expect("Failed to generate TreeNode from [Vec<i32>]")
178+
/// );
179+
/// ```
180+
///
181+
/// Making a tree only towards the right side:
182+
///
183+
/// ```rust
184+
/// use std::{cell::RefCell, rc::Rc};
185+
/// use leetcode_trees_rs::utils::{tree, symmetric_tree, TreeNode};
186+
///
187+
/// let node_right_sided = TreeNode {
188+
/// val: 1,
189+
/// left: None,
190+
/// right: Some(Rc::new(RefCell::new(TreeNode {
191+
/// val: 3,
192+
/// left: Some(Rc::new(RefCell::new(TreeNode::new(7)))),
193+
/// right: Some(Rc::new(RefCell::new(TreeNode::new(8)))),
194+
/// }))),
195+
/// };
196+
/// assert_eq!(
197+
/// Rc::new(RefCell::new(node_right_sided)),
198+
/// tree!(
199+
/// &[
200+
/// vec![Some(1)],
201+
/// vec![None, Some(3)],
202+
/// // The other `None` values are inferred from their parents.
203+
/// //
204+
/// // **IMPORTANT:** Don't add them in because it causes errors!
205+
/// vec![/*None, None, */ Some(7), Some(8)],
206+
/// ]
207+
/// ).expect("Failed to generate TreeNode from [Vec<i32>]")
208+
/// );
209+
/// ```
210+
///
211+
/// Utilizig both sides in making a tree:
212+
///
213+
/// ```rust
214+
/// use std::{cell::RefCell, rc::Rc};
215+
/// use leetcode_trees_rs::utils::{tree, symmetric_tree, TreeNode};
216+
///
217+
/// let node_both_sided = TreeNode {
218+
/// val: 1,
219+
/// left: Some(Rc::new(RefCell::new(TreeNode {
220+
/// val: 2,
221+
/// left: Some(Rc::new(RefCell::new(TreeNode::new(5)))),
222+
/// right: Some(Rc::new(RefCell::new(TreeNode::new(6)))),
223+
/// }))),
224+
/// right: Some(Rc::new(RefCell::new(TreeNode {
225+
/// val: 3,
226+
/// left: Some(Rc::new(RefCell::new(TreeNode::new(7)))),
227+
/// right: Some(Rc::new(RefCell::new(TreeNode::new(8)))),
228+
/// }))),
229+
/// };
230+
/// assert_eq!(
231+
/// Rc::new(RefCell::new(node_both_sided)),
232+
/// tree!(
233+
/// &[
234+
/// vec![Some(1)],
235+
/// vec![Some(2), Some(3)],
236+
/// vec![Some(5), Some(6), Some(7), Some(8)],
237+
/// ]
238+
/// ).expect("Failed to generate TreeNode from [Vec<i32>]")
239+
/// );
240+
/// ```
241+
///
242+
/// ## Performance
243+
///
244+
/// The way this is implemented is with depth traversal (similiar to [Breath-First
245+
/// Search](https://en.wikipedia.org/wiki/Breadth-first_search)) so the algorithm's performance is:
246+
///
247+
/// Worst-case time complexity: O(|V| + |E|) = O(b<sup>d</sup>)
248+
///
249+
/// Worst-case space complexity: O(|V|) = O(b<sup>d</sup>)
250+
///
251+
/// Where:
252+
///
253+
/// V = Verticies and E = Edges
254+
#[macro_export]
60255
macro_rules! tree {
61-
($val:expr) => {
62-
$crate::utils::TreeNode::new($val)
63-
};
64-
($($left:tt, $right:tt)*) => {
65-
$(
66-
if let Some(left) = $left {
67-
$node.left = Some(std::rc::Rc::new(std::cell::RefCell::new(tree!(
68-
left
69-
))));
70-
}
71-
if let Some(right) = $right {
72-
$node.right = Some(std::rc::Rc::new(std::cell::RefCell::new(tree!(
73-
right
74-
))));
75-
}
76-
)*
77-
};
78-
($val:expr, $($left:expr, $right:expr)*) => {
79-
{
80-
let mut node = $crate::utils::TreeNode::new($val);
81-
$(
82-
tree!(node, ($left, $right));
83-
)*
84-
node
85-
}
86-
};
256+
($items:expr) => {{
257+
$crate::macros::helper_functions::_build_tree($items)
258+
}};
87259
}
88260

89261
/// ## Description
@@ -102,6 +274,7 @@ macro_rules! tree {
102274
/// symmetric) as an argument (and builds the `TreeNode` struct with them).
103275
///
104276
/// ## Example usage
277+
///
105278
/// ```rust
106279
/// use leetcode_trees_rs::utils::symmetric_tree;
107280
/// symmetric_tree!(1, 2, 3, 4);
@@ -175,6 +348,23 @@ macro_rules! tree {
175348
/// };
176349
/// assert_eq!(node, symmetric_tree!(1, 2, 3, 4));
177350
/// ```
351+
///
352+
/// Another way of desugaring this symmetric tree is with the tree!() macro like so:
353+
///
354+
/// ```rust
355+
/// use std::{rc::Rc, cell::RefCell};
356+
/// use leetcode_trees_rs::utils::{symmetric_tree, tree};
357+
/// assert_eq!(
358+
/// tree!(
359+
/// &mut [
360+
/// vec![Some(1)],
361+
/// vec![Some(2), Some(2)],
362+
/// vec![Some(3), Some(3), Some(3), Some(3)],
363+
/// vec![Some(4), Some(4), Some(4), Some(4), Some(4), Some(4), Some(4), Some(4)],
364+
/// ]
365+
/// ).unwrap(),
366+
/// Rc::new(RefCell::new(symmetric_tree!(1, 2, 3, 4))));
367+
/// ```
178368
#[macro_export]
179369
macro_rules! symmetric_tree {
180370
($val:expr) => {

‎src/utils/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ pub use crate::list_node;
2222
/// A re-export for the symmetric_tree!, right_tree! and left_tree! macros.
2323
/// All of the TreeNode macros can be used to also just generate a new `TreeNode` instance without
2424
/// expanding on it.
25-
pub use crate::{left_tree, right_tree, symmetric_tree};
25+
pub use crate::{left_tree, right_tree, symmetric_tree, tree};

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /