I am implementing node deletion in binary search tree. I have implemented a method which look good (at algorithm standpoint). But do not work. After spending hours trying to understand why, I would love to get some help from you.
BST definition
type Node struct {
Data int
Left *Node
Right *Node
}
Helper methods (they have been tested and works)
// New returns a pointer to a mew node (like the new construct in Go)
func New(data int) *Node {
return &Node{Data: data}
}
// Find checks whether some data exist in the bst and returns the corresponding node
func (bst *Node) Find(data int) *Node {
if bst == nil {
return bst
}
if bst.Data == data {
return bst
}
if data < bst.Data {
return bst.Left.Find(data)
}
return bst.Right.Find(data)
}
// Min returns the smallest element in a bst
func (bst *Node) Min() *Node {
if bst == nil {
return nil
}
current := bst
for current.Left != nil {
current = current.Left
}
return current
}
The non working method
// Delete removes a key from the binary tree
func (bst *Node) Delete(data int) *Node {
if bst == nil {
return bst
}
current := bst
toDelete := current.Find(data)
if toDelete == nil {
return current
}
if toDelete.Right == nil && toDelete.Left != nil {
toDelete = toDelete.Left
return current
}
if toDelete.Right != nil && toDelete.Left == nil {
toDelete = toDelete.Right
return current
}
inOrderSuccessor := toDelete.Right.Min()
toDelete = inOrderSuccessor
return current
}
Test
func main() {
root := bst.New(8)
root.Left = bst.New(3)
root.Right = bst.New(10)
root.Left.Left = bst.New(1)
root.Left.Right = bst.New(6)
fmt.Println(root.InOrder())
root = root.Delete(3)
fmt.Println(root.InOrder())
}
output
1->3->6->8->10->
1->3->6->8->10->
There is something wrong in the Delete method but I could not understand why.
This code can be run in the playground here https://go.dev/play/p/oJZMOCp2BXL
I assume that you think that
toDelete = toDelete.Left
overwrites data that is stored where toDelete points to.
But this operation will just assign a new pointer to toDeletevariable. To overwrite data that is stored in memory you need to dereference the pointer:
*toDelete = *toDelete.Left
You can look at this example https://go.dev/play/p/M62hd3lpHXk and see the difference in a simpler case.
Related
I'm learning Go to prepare for a coding interview, and there's a leetcode question for tree traversal. It works with recursion in Python, but Golang behaves differently.
I notice the elements in the res slice gets cleared one by one when every call stack is popped.
The original question is
The result should be [1,3,5,6,2,4], and it was returned correctly in Python, but the following Go code returns []
/**
* Definition for a Node.
* type Node struct {
* Val int
* Children []*Node
* }
*/
func preorder(root *Node) []int {
res := []int{}
traverse(root, res)
return res
}
func traverse(root *Node, res []int){
if root == nil{
return
}
res = append(res, root.Val)
for _, n := range root.Children{
traverse(n, res)
}
// the last element is removed from the slice every time when the code execution reaches here
}
------------------------------------- updates --------------------------------------
Thanks for all your answers, now I think I have a better understanding of how slice works in Go
The following code works for me now:
/**
* Definition for a Node.
* type Node struct {
* Val int
* Children []*Node
* }
*/
func preorder(root *Node) []int {
res := []int{}
res = traverse(root, res)
return res
}
func traverse(root *Node, res []int) []int{
if root == nil{
return res
}
res = append(res, root.Val)
for _, n := range root.Children{
res = traverse(n, res)
}
return res
}
you can consider passing the res as a pointer *[]int instead so that the values get updated to the same slice else you are just passing a copy of it.
In your terminating case, you're not returning the accumulator:
if root == nil{
return
}
But...
I would use a closure so as to avoid cloning the slice on every recursive call (Go passes by value):
type Node struct {
Val int
Children []*Node
}
func preorder(root *Node) (res []int) {
var traverse func(*Node)
traverse = func(root *Node) {
if root != nil {
res = append(res, root.Val)
for _, n := range root.Children {
traverse(n)
}
}
}
traverse(root)
return res
}
I'm trying to create a BST, add a node, and print the data in that node, but I keep getting invalid memory address or nil pointer dereference errors. I know something is wrong with my pointers, and I've been fiddling around with them all afternoon, and I can't seem to get it right. Could someone please take a look and let me know what stupid mistake I'm making?
package main
import "fmt"
type node struct {
data int
left *node
right *node
}
type root struct {
root *node
}
func (bt root) addNode(n *node, data int) {
if n == nil {
newNode := node{
data: data,
left: nil,
right: nil,
}
n = &newNode
fmt.Println("Works")
} else if data < n.data {
bt.addNode(n.left, data)
} else {
bt.addNode(n.right, data)
}
}
func main() {
tree := root{root: nil}
tree.addNode(tree.root, 6)
fmt.Println(tree.root.data)
}
https://go.dev/play/p/Cps4Y5mqYFM
As kostix correctly pointed out, in order to modify my tree with that method, I had to pass in a pointer to a pointer to the original tree. Thanks, kostix!
package main
import "fmt"
type node struct {
data int
left *node
right *node
}
type root struct {
root *node
}
func (bt root) addNode(n **node, data int) {
if *n == nil {
newNode := node{
data: data,
left: nil,
right: nil,
}
*n = &newNode
fmt.Println("Works")
} else if data < (*n).data {
bt.addNode(&((*n).left), data)
} else {
bt.addNode(&((*n).right), data)
}
}
func main() {
tree := root{root: nil}
tree.addNode(&(tree.root), 6)
fmt.Println(tree.root.data)
}
So I am trying to retrieve a node in a minheap tree by index. The way that it would be called is that I would intiatate a empty MinHeapNode struct and pass by its value via &node so that between recursive function calls, if a match was found it would then return. However it seems that even given a found result the newly assigned empty node would be overwritten by another recursive call that has an empty version of that node. I'm still getting used to the idea of pointers and addresses so I believed that passing the values address would get around this since it would be calling the same value at the same address between calls. But apparently this is something is not correct.
type MinHeapNode struct {
Parent *MinHeapNode
Left *MinHeapNode
Right *MinHeapNode
Value int
Index int
}
func (MHN *MinHeapNode) Insert(value int) {
if !MHN.hasLeftChild() {
MHN.Left = &MinHeapNode{Parent: MHN, Value: value}
return
}
if !MHN.hasRightChild() {
MHN.Right = &MinHeapNode{Parent: MHN, Value: value}
return
}
if MHN.hasLeftChild(){
MHN.Left.Insert(value)
return
}
if MHN.hasRightChild(){
MHN.Right.Insert(value)
return
}
}
func (MHN *MinHeapNode) setIndex(count *int){
index := *count
*count = *count +1
MHN.Index = index
if MHN.hasLeftChild(){
MHN.Left.setIndex(count)
}
if MHN.hasRightChild(){
MHN.Right.setIndex(count)
}
}
func (MHN *MinHeapNode) getIndex(index int, node *MinHeapNode){
if MHN == nil{
return
}
if MHN.Index == index{
node = MHN
return
}
MHN.Left.getIndex(index, node)
MHN.Right.getIndex(index,node)
}
}
type MinHeapTree struct {
Root MinHeapNode
Size int
}
func (MHT *MinHeapTree) getIndex(index int)(*MinHeapNode, error){
if MHT.Size < index +1 {
err := fmt.Errorf("index exceeds tree size")
return nil, err
}
var node MinHeapNode
MHT.Root.getIndex(index, &node)
return &node, nil
}
The issue you are facing appears to be with the statement node = MHN in getIndex (but as your code is incomplete I cannot confirm if this is the only issue).
node = MHN will update the value of node (a parameter, so passed by value and, its scope is the function body). This has no impact on the value of the MinHeapNode that node pointed to at the start of the function. To correct this use *node = *MHN.
This can be demonstrated with a simple program (playground)
type MinHeapNode struct {
Test string
}
func getIndexBad(node *MinHeapNode) {
newNode := MinHeapNode{Test: "Blah"}
node = &newNode
}
func getIndexGood(node *MinHeapNode) {
newNode := MinHeapNode{Test: "Blah"}
*node = newNode
}
func main() {
n := MinHeapNode{}
fmt.Println(n)
getIndexBad(&n)
fmt.Println(n)
getIndexGood(&n)
fmt.Println(n)
}
The output demonstrates that the "bad" function does not update the passed in node:
{}
{}
{Blah}
I want to create a binary tree and initialize the tree use golang.
And the codes like these:
package Tree
import "fmt"
type TreeNode struct {
Left *TreeNode
Right *TreeNode
Value int
}
func InsertNodeToTree(tree *TreeNode, node *TreeNode)(){
if tree == nil {
tree = node
}
if node.Value > tree.Value {
InsertNodeToTree(tree.Right, node)
}
if node.Value < tree.Value {
InsertNodeToTree(tree.Left, node)
}
}
func InitTree(values ...int) (root *TreeNode) {
rootNode := TreeNode{Value: values[0]}
for _, value := range values {
node := TreeNode{Value:value}
InsertNodeToTree(&rootNode, &node)
}
return &rootNode
}
func main() {
treeNode := InitTree(5, 4, 6, 8, 9, 7, 1, 3, 2)
fmt.Println(treeNode)
}
Why the tree's left and right are nil?
I pass the reference of the tree node, why not work?
In C/C++ programming language, you can use TreeNode *&tree.
But in golang programming language, you can not use *&.
tree is just a copy of the pointer, so you can't point the value to another TreeNode.
I modified your program, and it can run successfully now.
Maybe these codes you need:
package Tree
type TreeNode struct {
Left *TreeNode
Right *TreeNode
Value int
}
var DefaultValue int = -1024
func InsertNodeToTree(tree *TreeNode, node *TreeNode)(){
if tree == nil {
return
}
if tree.Value == DefaultValue {
tree.Value = node.Value
return
}
if node.Value > tree.Value {
if tree.Right == nil {
tree.Right = &TreeNode{Value: DefaultValue}
}
InsertNodeToTree(tree.Right, node)
}
if node.Value < tree.Value {
if tree.Left == nil {
tree.Left = &TreeNode{Value: DefaultValue}
}
InsertNodeToTree(tree.Left, node)
}
}
func InitTree(values ...int) (root *TreeNode) {
rootNode := TreeNode{Value: DefaultValue, Right: nil, Left: nil}
for _, value := range values {
node := TreeNode{Value:value}
InsertNodeToTree(&rootNode, &node)
}
return &rootNode
}
tree is only a copy of the pointer. Assigning to the variable is useless. Instead, you need to assign to an already existing node. For example:
https://play.golang.org/p/Agzby-Yinq
func InsertNodeToTree(tree *TreeNode, node *TreeNode) {
if tree == nil {
panic("cannot insert into nil root")
}
if node.Value > tree.Value {
if tree.Right == nil {
tree.Right = node
} else {
InsertNodeToTree(tree.Right, node)
}
}
if node.Value < tree.Value {
if tree.Left == nil {
tree.Left = node
} else {
InsertNodeToTree(tree.Left, node)
}
}
}
I'd like some help please on how Go pointer receivers work.
I have a contained example below of a binary search tree which hopefully helps me explain.
package main
import "fmt"
type Node struct {
key int
left, right *Node
}
func NewNode(key int) *Node {
return &Node{key, nil, nil}
}
type BST struct {
root *Node
}
func NewBinarySearchTree() *BST {
return &BST{nil}
}
func (t *BST) Insert(key int) {
if t.root == nil {
t.root = NewNode(key)
return
}
var node = t.root
for {
if key < node.key {
if node.left == nil {
node.left = NewNode(key)
return
} else {
node = node.left
}
} else {
if node.right == nil {
node.right = NewNode(key)
return
} else {
node = node.right
}
}
}
}
func inorder(node *Node) {
if node == nil {
return
}
inorder(node.left)
fmt.Print(node.key, " ")
inorder(node.right)
}
func main() {
tree := NewBinarySearchTree()
tree.Insert(3)
tree.Insert(1)
tree.Insert(2)
tree.Insert(4)
inorder(tree.root) // 1 2 3 4
}
After I wrote this, however, I thought I could simplify my insert function as follows:
func (t *BST) Insert2(key int) {
var node *Node
node = t.root
for node != nil {
if key < node.key {
node = node.left
} else {
node = node.right
}
}
node = NewNode(key)
}
However, doing it this way the tree is never updated.
My thinking was...
on the first insert the root node will be nil.
so the local variable node which references t.root will also be nil
the for loop will therefore be skipped.
node = NewNode(key) will have the same effect as t.root =
NewNode(key)
Where does my Insert2 method go wrong? Is there a way it can be tweaked?
You seem to be confusing the usage of pointers.
When you do node = t.root, you merely makes node point to whatever t.root points to.
Later on, when you do node = NewNode(key), you make node points to a newly created item, which is not what you wanted; you want to make t.root point to that new item instead.
Since you intend to modify variables which are of type *Node (root, left and right), we need a pointer to them, so a variable of type **Node, with one more level of indirection.
You can start by making node point to the address of t.root, node := &t.root, then you proceed to your loop.
You can try something like the following:
func (t *BST) Insert3(key int) {
node := &t.root
for *node != nil {
if key < (*node).key {
node = &(*node).left
} else {
node = &(*node).right
}
}
*node = NewNode(key)
}
Pay attention that we use the indirection operator * to access the referenced data, when checking the address on the loop, and also the key.
In the end of the function, *node = NewNode(key) does what you intended to do originally; you are assigning the newly created item to the root, left or right pointers.
node = NewNode(key)
That line doesn't change the tree. That line changes the local variable node; after this line, node points to a different Node, but the object it used to point to is unaffected. To insert into the tree, you have to assign to t.root, node.left, or node.right.