Stack using Array

Stack using Array

Golang code for Stack using Array

package main

import (
	"errors"
	"fmt"
)

type stack struct {
	arr [10]int
	top int
}


func (s *stack) push(item int) error {
	if s.top < len(s.arr)-1 {
		s.top = s.top + 1
		s.arr[s.top] = item
		return nil
	}
	return errors.New("Stack capacity is full")
}

func (s *stack) pop() (int, error) {
	if s.top > -1 {
		item := s.arr[s.top]
		s.top = s.top - 1
		return item, nil
	}
	return -1, errors.New("Stack is empty")
}

// Renamed function to avoid confusion with field "top"
func (s *stack) topElement() (int, error) {
	if s.top > -1 {
		return s.arr[s.top], nil
	}
	return -1, errors.New("Stack is empty")
}

func (s *stack) size() int {
	return s.top + 1
}

func main() {
	s := stack{
		// arr: [10]int{}, // No need to initialize an array like this
		top: -1,
	}

	err := s.push(10)
	if err ! = nil {
		fmt.Println("Error occurred in push operation:", err.Error())
	}

	err = s.push(20)
	if err ! = nil {
		fmt.Println("Error occurred in push operation:", err.Error())
	}

	err = s.push(30)
	if err ! = nil {
		fmt.Println("Error occurred in push operation:", err.Error())
	}

	item, err := s.topElement()
	if err ! = nil {
		fmt.Println("Error occurred in finding top operation:", err.Error())
	} else {
		fmt.Printf("Top=%d\n", item)
	}

	fmt.Printf("Size of stack=%d\n", s.size())

	item, err = s.pop()
	if err ! = nil {
		fmt.Println("Error occurred in pop operation:", err.Error())
	} else {
		fmt.Printf("Popped Top=%d\n", item)
	}
}

Variations of usage of type struct

When to Use Value Receiver (Pass-by-Value)

You can and should use pass-by-value in certain cases, especially when:

  • No modification is needed:
    • If your method only reads the data from the struct without changing it, using a value receiver is fine.
      • Example: Calculating or printing some information based on the struct’s fields.
func (s stack) isEmpty() bool { 
  return s.top == -1 
}
  • The struct is small:
    • If the struct is small, copying it is not costly, and passing it by value may be more efficient.
      • Small structs like struct { x, y int } are cheap to copy because they only take a small amount of memory.
type Point struct {
    x, y int
}

func (p Point) distance() int {
    return p.x * p.x + p.y * p.y
}
  • Immutable operations: When you explicitly want to create a copy of the struct and ensure the original doesn’t get modified, passing by value guarantees this immutability.
    • Example: When you want to perform operations on a copy of the struct, but you don’t want to modify the original struct.

When to Use Pointer Receiver (Pass-by-Pointer)

You should use pass-by-pointer when:

You need to modify the original struct: If the method changes the state of the struct (like modifying fields), you should use a pointer receiver to ensure the original instance is modified.

func (s *stack) push(item int) {
    s.top++
    s.arr[s.top] = item
}

The struct is large: If the struct contains a lot of fields or large data (e.g., large arrays, maps, or slices), copying the entire struct is inefficient. In such cases, passing a pointer avoids unnecessary copying and improves performance.

type LargeData struct {
    data [10000]int
}

func (l *LargeData) process() {
    // Modify or process data
}

Avoiding excessive copies: If a method is called frequently or the struct is used in multiple places, it may be better to use pointer receivers to avoid making too many copies and save memory.

General Guidelines

Pass-by-value (value receiver)

  • Use when the struct is small and you don’t need to modify it.
  • Ideal for read-only methods or when immutability is desired.
  • Efficient for small structs or when copying is cheaper than dereferencing a pointer.

Pass-by-pointer (pointer receiver)

  • Use when you need to modify the struct.
  • Use for large structs to avoid unnecessary copying.
  • Ensures that the method works on the original instance, not a copy.

Example: When to Use Each

// Value receiver: does not modify the original stack, just reads it.
func (s stack) isEmpty() bool {
    return s.top == -1
}

// Pointer receiver: modifies the original stack.
func (s *stack) push(item int) {
    if s.top < len(s.arr)-1 {
        s.top++
        s.arr[s.top] = item
    }
}

Conclusion

  • You don’t need to always use pass-by-pointer for structs.
  • Use pass-by-value when you only need to read data and the struct is small.
  • Use pass-by-pointer when you need to modify the struct or avoid unnecessary copying for large structs.

Visit https: https://codeandalgo.com for more such contents

Leave a Reply

Your email address will not be published. Required fields are marked *