I am writing a binary tree structure, and I have problems at the insert function. After calling the function to insert data in my node, the node is not modified.
use std::ptr;
#[derive(Clone, Copy)]
struct Node<T> {
data: Option<T>,
left: *mut Node<T>,
right: *mut Node<T>,
}
impl<T> Node<T> {
pub fn new(data: T) -> Node<T> {
Node {
data: Some(data),
left: ptr::null_mut(),
right: ptr::null_mut(),
}
}
pub fn insert(mut self, data: T) {
let tmp = self.data.unwrap();
self.data = None;
self.left = &mut Node::new(data);
self.right = &mut Node::new(tmp);
}
}
impl<T: std::fmt::Display> std::fmt::Display for Node<T>
where T: std::fmt::Debug
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.data {
Some(ref x) => {
write!(f, "Node data: {}, left: {}, right: {}", x,
if self.left.is_null() {"null"} else {"not null"},
if self.right.is_null() {"null"} else {"not null"},
)
}
None => {
write!(f, "Node data: None, left: {}, right: {}",
if self.left.is_null() {"null"} else {"not null"},
if self.right.is_null() {"null"} else {"not null"},
)
}
}
}
}
fn main() {
let mut root: Node<i32> = Node::new(32);
println!("Root before insert : {}", root);
root.insert(42);
println!("Root after insert: {}", root);
}
And a trace of execution
Root before insert : Node data: 32, left: null, right: null
Root after insert : Node data: 32, left: null, right: null
My node is not modified after the function insert. What can I do to solve this?
Since you appear to be quite confused, let's get you started!
First of all, there is no reason to use raw pointers. Furthermore, I advise AGAINST using Copy as it just hides ownership issues. Finally, it's much easier to derive Debug than implement the formatting manually (and it allows experimenting with the layout of the struct in a more automated fashion).
#[derive(Debug)]
struct Node<T> {
data: Option<T>, // are you sure about using Option here?
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
So, instead of raw pointers, we use a Box pointer which we place into an Option to handle the null case.
The construction is now:
impl<T> Node<T> {
fn new(data: T) -> Node<T> {
Node {
data: Some(data),
left: None,
right: None,
}
}
}
Nothing outstanding, let's move on to insert:
impl<T> Node<T> {
fn insert(&mut self, data: T) {
let current = self.data.take().expect("Cannot insert in empty node!");
self.left = Some(Box::new(Node::new(current)));
self.right = Some(Box::new(Node::new(data)));
}
}
And we can move on to the display (using Debug with "{:?}"):
fn main() {
let mut root: Node<i32> = Node::new(32);
println!("Root before insert : {:?}", root);
root.insert(42);
println!("Root after insert: {:?}", root);
}
And it works!
Related
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
pub val: i32,
pub left: Option<Rc<RefCell<TreeNode>>>,
pub right: Option<Rc<RefCell<TreeNode>>>,
}
impl TreeNode {
#[inline]
pub fn new(val: i32) -> Self {
TreeNode {
val,
left: None,
right: None,
}
}
pub fn invalid_path_error(self) {
panic!("Invalid path");
}
pub fn insert(&mut self, directions: &[&str], val: i32) {
let mut cur_node = &mut None;
let l = directions.len();
if directions[0] == "left" {
cur_node = &mut self.left;
}
if directions[0] == "right" {
cur_node = &mut self.right;
}
for dir in &directions[1..] {
let mut n;
if *dir == "left" {
if let Some(z) = cur_node {
n = &mut z.borrow_mut().left;
} else {
panic!("Invalid path");
}
}
if *dir == "right" {
if let Some(z) = cur_node {
n = &mut z.borrow_mut().right;
} else {
panic!("Invalid path");
}
}
cur_node = n;
}
//cur_node = Some(Rc::new(RefCell::new(TreeNode::new(2))));
}
}
I am trying to learn rust by solving some leet code questions. I am trying to implement insert function for binary tree. This is the struct given in leet code. I am trying to implement insert by pass list of strings for path For eg. go left , right , left etc. After traversing at the end I will add new node. I am trying to use cur node as a temp pointer and want to change it with each string. But every time I get this error - " temporary value dropped while borrowed consider using a let binding to create a longer lived value ". How can I fix this and implement insert ?
cargo check -
Here's a solution that replaces Rc<RefCell<_>> with Box<_>. Generally you only need to reach for Rc when multiple people will want ownership over the underlying data. In this case, each node is only owned by one other node, so Box is preferable.
This solution iterates through the tree to find the last node, then uses the last direction to assign to the correct child node. No checks are implemented to make sure that the nodes along the path exist or that an existing node isn't being overwritten.
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
pub val: i32,
pub left: Option<Box<TreeNode>>,
pub right: Option<Box<TreeNode>>,
}
impl TreeNode {
#[inline]
pub fn new(val: i32) -> Self {
TreeNode {
val,
left: None,
right: None,
}
}
pub fn insert(&mut self, directions: &[&str], val: i32) {
let mut cur_node = self;
let len = directions.len();
let mut directions = directions.into_iter().copied();
for direction in directions.by_ref().take(len - 1) {
let child_node = match direction {
"left" => &mut cur_node.left,
"right" => &mut cur_node.right,
_ => panic!("invalid direction {direction}"),
};
cur_node = child_node.as_mut().expect("invalid path").as_mut();
}
let new_node = Some(Box::new(TreeNode::new(val)));
match directions.next().unwrap() {
"left" => cur_node.left = new_node,
"right" => cur_node.right = new_node,
direction # _ => panic!("invalid direction {direction}"),
}
}
}
fn main() {
let mut tree = TreeNode::new(0);
tree.insert(&["left"], 1);
tree.insert(&["right"], 2);
tree.insert(&["left", "left"], 2);
tree.insert(&["right", "left"], 3);
println!("{:#?}", tree);
}
Prints
TreeNode {
val: 0,
left: Some(
TreeNode {
val: 1,
left: Some(
TreeNode {
val: 2,
left: None,
right: None,
},
),
right: None,
},
),
right: Some(
TreeNode {
val: 2,
left: Some(
TreeNode {
val: 3,
left: None,
right: None,
},
),
right: None,
},
),
}
I have a BSTNode struct with an insert function in it:
pub struct BSTNode {
pub value: i32,
pub left: Option<Box<BSTNode>>,
pub right: Option<Box<BSTNode>>,
}
impl BSTNode {
pub fn insert(&mut self, val: i32) {
if val <= self.value {
match self.left {
None => {
self.left = Some(Box::new(BSTNode {
value: val,
left: None,
right: None,
}))
}
Some(ref mut node) => node.insert(val),
}
} else {
match self.right {
None => {
self.right = Some(Box::new(BSTNode {
value: val,
left: None,
right: None,
}))
}
Some(ref mut node) => node.insert(val),
}
}
}
}
I also have a BST struct to store that Node
struct BST {
node: Option<BSTNode>,
}
Is it possible to call the insert func implemented on the BSTNode through the BST struct?
What I mean is, that in the main.rs I could do this:
let mut root = BST::BST::new();
root.insert(5) // getting error obviously because method does not exist on BST struct.
Is it possible to kind of point to that BSTNode method what I call 'insert' through the BST struct?
I tried to just implement this method in the BST struct instead of keeping it in the BSTNode struct, but I am encountering a lot of problems, although that will be my last resort.
Keep it simple stupid solution: Just make an explicit delegator.
impl BST {
pub fn insert(&mut self, val: i32) {
if let Some(node) = self.node.as_mut() {
node.insert(val);
}
}
}
No need to reimplement anything, and the extra function call will almost certainly get inlined out unless you go out of your way to impede optimizations.
I am programing a LinkedList. Here is My Struct, I need some help on performing a get by index (usize) method.
Here is My Struct Code:
struct Node<T>
where
T: Clone,
{
value: T,
prev: Option<Rc<RefCell<Node<T>>>>,
next: Option<Rc<RefCell<Node<T>>>>,
}
impl<T> Node<T>
where
T: Clone,
{
pub fn new(val: T) -> Self {
Node {
value: val,
prev: None,
next: None,
}
}
}
struct ListNode<T: Clone> {
length: usize,
header: Option<Rc<RefCell<Node<T>>>>,
tail: Option<Rc<RefCell<Node<T>>>>,
}
Now I want to perform a get method to get T by an index:usize, There is a problem
impl<T> ListNode<T>
where
T: Clone,
{
pub fn get(&self, idx: usize) -> Option<T> {
let mut p = &self.header;
for _ in 0..=idx {
if let Some(x) = p {
let clone_p = Rc::clone(x);
// Problem 1 is here, I want p point to the next
p = &((*clone_p).borrow().next);
} else {
return None;
}
}
if let Some(x) = p {
let clone_p = Rc::clone(x);
return Some((*clone_p).borrow().value.clone());
}
None
}
}
How to fix this?
I think I have to clone the ReCell, Here is the code, any optimization?
pub fn get(&self, idx: usize) -> Option<T> {
if let Some(p) = &self.header {
let mut ptr: Option<Rc<RefCell<Node<T>>>> = None;
for _ in 0..=idx {
let v = Rc::clone(p);
let next = &(*v).borrow().next;
if let Some(x) = next {
ptr = Some(Rc::clone(x));
} else {
return None;
}
}
if let Some(x) = ptr {
return Some((*x).borrow().value.clone());
}
}
None
}
I'm very new to rust and I'm trying to creating an AVL Tree. I used Rc because I want every node to be owned by nodes above it and RefCell to have it mutable internally.
I've started to build the "insert" method, but it isn't inserting a new node in the correct place, rather its replace the "root" node with the new node and I'm having trouble understanding why. I believe that this may be an ownership issue but I'm not sure.
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
#[derive(Debug)]
pub struct BaseNode {
pub key: u32,
pub left: AvlTree,
pub right: AvlTree,
}
pub type AvlNode = Rc<RefCell<BaseNode>>;
pub type AvlTree = Option<AvlNode>;
impl BaseNode {
fn new(key: u32) -> Self {
Self {
key: key,
left: None,
right: None,
}
}
}
trait AvlNodeTrait {
fn new_node(key: u32) -> Self;
}
impl AvlNodeTrait for AvlNode {
fn new_node(key: u32) -> Self {
Rc::new(RefCell::new(BaseNode::new(key)))
}
}
pub trait AvlTreeTrait {
fn new() -> Self;
fn left(&self) -> Self;
fn right(&self) -> Self;
fn insert(&mut self, key: u32);
fn dupe(&self) -> Self;
fn set(&mut self, node: AvlNode);
}
impl AvlTreeTrait for AvlTree {
fn new() -> Self {
None
}
fn left(&self) -> Self {
if let Some(node) = self {
return node.borrow().right.dupe();
}
panic!("Trying to get Left of None!")
}
fn right(&self) -> Self {
if let Some(node) = self {
return node.borrow().right.dupe();
}
panic!("Trying to get right of None!")
}
fn dupe(&self) -> Self {
match self {
Some(node) => Some(Rc::clone(&node)),
None => None,
}
}
fn set(&mut self, node: AvlNode) {
*self = Some(Rc::clone(&node));
}
fn insert(&mut self, key: u32) {
let node = AvlNode::new_node(key);
let mut curr_tree = self;
let mut curr_key = 0;
while !curr_tree.is_none() {
if let Some(node) = &curr_tree {
curr_key = node.borrow().key;
if key > curr_key {
*curr_tree = curr_tree.left()
} else if key < curr_key {
*curr_tree = curr_tree.right()
} else {
return;
}
}
}
*curr_tree = Some(Rc::clone(&node));
}
}
fn main() {
let mut tree = AvlTree::new();
println!("{:?}", tree); // None
tree.insert(5);
println!("{:?}", tree); // Some(RefCell { value: BaseNode { key: 5, left: None, right: None } })
tree.insert(56);
println!("{:?}", tree); // Some(RefCell { value: BaseNode { key: 2, left: None, right: None } })
}
I would say the use of RefCell is quite unnecessary and potentially unsafe in this context. RefCell hands over the ownership/borrow checking to the runtime instead of doing them during compile time. This can lead to your program to panic in case it violates any of the borrowing rules.
I would prefer a "recursive" type looking something like this:
struct AVLTree<T> {
val: T,
left: Option<Box<AVLTree<T>>>,
right: Option<Box<AVLTree<T>>>
}
This will of course introduce some overhead due to memory allocation.
I am writing a basic binary tree structure and I want to display a node. It seems that Rust has trouble displaying a generic type, and I get this error:
error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied
--> src/main.rs:55:60
|
55 | write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
| ^^^^^^^^^ trait `T: std::fmt::Display` not satisfied
|
= help: consider adding a `where T: std::fmt::Display` bound
= note: required by `std::fmt::Display::fmt`
error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied
--> src/main.rs:62:60
|
62 | write!(f, "Node data: {} left: {:?}, right: {:?}", self.data, self.left, self.right);
| ^^^^^^^^^ trait `T: std::fmt::Display` not satisfied
|
= help: consider adding a `where T: std::fmt::Display` bound
= note: required by `std::fmt::Display::fmt`
Here's the full code, including the iterators
struct Node<T> {
data: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
struct NodeIterator<T> {
nodes: Vec<Node<T>>,
}
struct Tree<T> {
root: Option<Node<T>>,
}
impl<T> Node<T> {
pub fn new(value: Option<T>,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>)
-> Node<T> {
Node {
data: value.unwrap(),
left: left,
right: right,
}
}
pub fn insert(&mut self, value: T) {
println!("Node insert");
match self.left {
Some(ref mut l) => {
match self.right {
Some(ref mut r) => {
r.insert(value);
}
None => {
self.right = Some(Box::new(Node::new(Some(value), None, None)));
}
}
}
None => {
self.left = Some(Box::new(Node::new(Some(value), None, None)));
}
}
}
}
impl<T> std::fmt::Display for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f,
"Node data: {} left: {:?}, right: {:?}",
self.data,
self.left,
self.right);
}
}
impl<T> std::fmt::Debug for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f,
"Node data: {} left: {:?}, right: {:?}",
self.data,
self.left,
self.right);
}
}
impl<T> Iterator for NodeIterator<T> {
type Item = Node<T>;
fn next(&mut self) -> Option<Node<T>> {
if self.nodes.len() == 0 {
None
} else {
let current: Option<Node<T>> = self.nodes.pop();
for it in current.iter() {
for n in it.left.iter() {
self.nodes.push(**n);
}
for n in it.right.iter() {
self.nodes.push(**n);
}
}
return current;
}
}
}
impl<T> Tree<T> {
pub fn new() -> Tree<T> {
Tree { root: None }
}
pub fn insert(&mut self, value: T) {
match self.root {
Some(ref mut n) => {
println!("Root is not empty, insert in node");
n.insert(value);
}
None => {
println!("Root is empty");
self.root = Some(Node::new(Some(value), None, None));
}
}
}
fn iter(&self) -> NodeIterator<T> {
NodeIterator { nodes: vec![self.root.unwrap()] }
}
}
fn main() {
println!("Hello, world!");
let mut tree: Tree<i32> = Tree::new();
tree.insert(42);
tree.insert(43);
for it in tree.iter() {
println!("{}", it);
}
}
Here is a minimal version of this issue:
struct Bob<T>(T);
impl<T> std::fmt::Display for Bob<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
}
fn main() {
let x = Bob(4);
println!("{}", x);
}
Let's take a look at our fmt function:
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
We can rewrite it as follows for better clarity:
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: ")?;
std::fmt::Display::fmt(&self.0, f)
}
Calling one of the formatting macros (write!, format!, println!, etc.) with double brackets in quotes, "{}", says to call the fmt function from the Display trait for that argument (self.0 in this case).
The problem is that we have some generic type T, so the compiler has no idea whether Display is implemented for it or not.
There are two ways to fix this.
First, we could add the constraint T: std::fmt::Display to our implementation of Display for Bob. This will let us use the struct with non-Display types, but Display will only be implemented when we use it with Display types.
That fix looks like this:
impl<T: std::fmt::Display> std::fmt::Display for Bob<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Bob: {}", self.0)
}
}
Second, we could add that constraint to the struct definition, like this:
struct Bob<T: std::fmt::Display>(T);
This will mean that Bob is only generic with regards to types that are Display. It is more limiting and restricts the flexibility of Bob, but there may be cases where that is desired.
There are other traits similar to Display that can be called by putting different tokens in the brackets. The full list can be found in the documentation, but, for example, we could use the Debug trait with
write!(f, "Bob: {:?}", self.0)
only then we would need to be sure that T is std::fmt::Debug.