Searching and Returning a node using recursion in minheap binary tree - go

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}

Related

Golang pointer receiver not updating as expected

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.

Trying to make a binary search tree, but I keep getting invalid memory address or nil pointer dereference errors

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)
}

In Go How to delete an item from slice of an Struct

I have struct containing a slice of another struct. I have added methods for Addition and Deletion of an item from the slice but addition is working deletion is not. I am new to Go so I am not able to understand why slice reassignment does not gets reflected in struct
Short Version of my code below. Link to PlayGoLang : http://play.golang.org/p/4NnGh3Dtzw
type BatteryTest struct {
Name, LocalConf, JdkPath, SysProps, LocalconfPath string
NumberOfNodes int
}
type Server struct {
Port int
TestQueue, CompletedTests, RunningTests []BatteryTest
}
func (this *Server) AddBatteryTest(test BatteryTest) error {
this.TestQueue = append(this.TestQueue, test)
return nil
}
func (this *Server) TakeBatteryTest() error {
length := len(this.TestQueue)
if length == 0 {
fmt.Println("Len==", 0)
return errors.New("Queue is empty")
}
slice := this.TestQueue
i := len(this.TestQueue) - 1
slice = append(slice[:i], slice[i+1:]...)
return nil
}
You are not assigning slice back to this.TestQueue

Reference type confusing in Go language

I tried to make Trie data structures by Go Language, but somehow it stuck with References problem,
Here it is. http://play.golang.org/p/ASSGF5Oe9R
// Package main provides ...
package main
import "fmt"
type RootTrie []Trie
type Trie struct {
subtrie []Trie
index byte
}
func (trie *Trie) Insert(data string) *Trie {
if data != "" {
if trie.index == 0 {
trie.index = data[0]
}
if next := trie.containsIndex(data[1:]); next != nil {
//Problem Point
fmt.Println(string(data[1]), "found follwing", string(data[0]))
next.Insert(data[1:])
} else {
nt := &Trie{}
trie.subtrie = append(trie.subtrie, *nt.Insert(data[1:]))
}
}
return trie
}
func (trie *Trie) containsIndex(next string) *Trie {
if next != "" {
for _, st := range trie.subtrie {
if st.index == next[0] {
return &st
}
}
}
return nil
}
func main() {
t := &Trie{}
t = t.Insert("hanyang")
fmt.Println("result:", t)
t = t.Insert("hanyKk")
fmt.Println("result:", t)
t.Insert("hanyK")
}
The following problems happen in second "Insert",
the where I put, //Problem Point
I made containsIndex method for searching next linked trie, and it searched well actually.
But when I updated next property which containsIndex given, its not affected its mother struct trie though.
What I don't understand is I gave it reference type when returning containsIndex, but its still
act liked 'value copied', Why does it not affected its mother structure(trie)?
Thanks!
The problem is in method containsIndex. Golang range by default creates copy each element in slice and assigns copy of this value to st (in your example). Usually to preserve reference to element in slice you should use original slice and its index. In you case method containsIndex should look something like this:
func (trie *Trie) containsIndex(next string) *Trie {
if next != "" {
for i, st := range trie.subtrie {
if st.index == next[0] {
return &trie.subtrie[i]
}
}
}
return nil
}

Why does my Go pointer receiver not cause an update?

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.

Resources