mutecipher

A data structure is a specialized format for organizing and storing data to make it accessible and efficient for computation.

Linked List

A Linked List is a linear data structure that consists of a sequence of nodes, each containing an element and a reference to the next node in the sequence. The first node is called the head or the beginning of the list. Nodes store data as well as pointers to the next nodes, creating a dynamic link between them. Linked Lists are commonly used when dealing with large data sets that need to be frequently modified, such as lists, queues, and stacks. The time complexity for common operations like insertion, deletion, and traversal is generally O(1) at the head of the list, but can vary depending on the implementation and location within the list. Space complexity for a Linked List is O(n), where n is the number of elements in the list.

Pros Cons
Dynamic data structure (shrink/grow at runtime) Requires more memory when compared to an array
No need to pre-allocate memory Traversing a linked list is more time consuming than an array
Stacks and Queues are often easily implemented using a linked list Random access is no possible due to it's dynamic nature
Insertion and deletion operations tend to be easier using a linked list Certain operations, such as searchinng, are slower using a linked list
Efficient for large datasets More complex to implement than an array
Ability to add or remove elements at any position Not ideal for small datasets over an array

Other implementations that should also be explored:

  • Singly linked lists
  • Doubly (Two way) linked lists
  • Circular linked lists
  • Circular doubly linked lists
class LinkedList
  attr_reader :head

  def initialize
    @head = nil
  end

  def append(value)
    if @head.nil?
      @head = Node.new(value)
      return
    end

    node = @head

    loop do
      break if node.next.nil?
      node = node.next
    end

    node.next = Node.new(value)
  end

  def append_after(n, value)
    node = @head
    new_node = Node.new(value)

    loop do
      break if node.nil?
      break if node == n
      node = node.next
    end

    temp = node.next
    node.next = new_node
    new_node.next = temp
  end

  def prepend(value)
    node = Node.new(value)
    node.next = @head
    @head = node
  end

  def prepend_before(n, value)
    new_node = Node.new(value)

    if @head == n
      temp = @head.next
      new_node.next = @head
      @head = new_node
      return
    end

    node = @head

    loop do
      break if node.next.nil?
      break if node.next == n
      node = node.next
    end

    temp = node.next
    node.next = new_node
    new_node.next = temp
  end

  def delete(value)
    node = @head

    loop do
      break if node.nil?
      break if node.next.value == value
      node = node.next
    end

    node.next = node.next.next
  end

  def delete_end
    node = @head

    loop do
      break if node.next.nil?
      node = node.next
    end

    node.next = nil
  end

  def delete_all
    @head = nil
  end

  def find(value)
    node = @head

    loop do
      break if node.nil?
      break if node.value == value
      node = node.next
    end

    return node
  end

  def values
    node = @head
    result = []

    loop do
      break if node.nil?
      result << node.value
      node = node.next
    end

    return result
  end

  def size
    values.length
  end
end

class Node
  attr_accessor :value, :next

  def initialize(value)
    @value = value
    @next = nil
  end
end

Stack

A Stack is a simple linear data structure that follows the Last-In, First-Out (LIFO) principle, meaning the last element added to the stack is the first one to be removed. The basic operations for a stack include push, which adds an element to the top of the stack, and pop, which removes the topmost element from the stack. Other common operations include peek, which returns the topmost element without removing it, and checking if the stack is empty or full. Stacks are commonly used for implementing function calls in programming languages, reverse iterations, and evaluating expressions with parentheses. The time complexity for most basic stack operations is O(1), making them highly efficient. Space complexity for a Stack is O(n), where n is the maximum number of elements it can hold.

Pros Cons
Easy to implement Limited capacity
Efficient memory utilization No random access
Fast access time Memory management
Enables undo/redo operations Stack overflow/underflow
Recursive function call limitations

This structure uses a Last in, first out (LIFO) principle.

class Stack
  attr_reader :items

  def initialize
    @items = Array.new
  end

  def push(item)
    @items.push(item)
  end

  def pop
    @items.pop
  end

  def size
    @items.length
  end
end

Queue

A Queue is a linear data structure that follows the First-In, First-Out (FIFO) principle, meaning the first element added to the queue is the first one to be removed. The basic operations for a queue include enqueue, which adds an element to the end of the queue, and dequeue, which removes the frontmost element from the queue. Other common operations include checking if the queue is empty or full and peeking at the frontmost element without removing it. Queues are commonly used in various applications such as message passing systems, real-time processing, and simulating different scenarios where data needs to be processed in the order they arrived. The time complexity for most basic queue operations is O(1), making them highly efficient. Space complexity for a Queue is O(n), where n is the maximum number of elements it can hold.

Pros Cons
Efficiently manage large amounts of data Insertion/deletion of elements from the middle are time consuming
Insertion/deletion of elements can be performed easily due to FIFO Limited space
Useful when used by multiple consumers Searching takes 0(n)
Fast for inter-process communication Maximum size must be defined prior (non-dynamic)
Used in the implementation of other data structures

This structure uses a First in, first out (FIFO) principle.

class Queue
  attr_reader :items

  def initialize
    @items = Array.new
  end

  def enqueue(item)
    @items.unshift(item)
  end

  def dequeue
    @items.pop
  end

  def size
    @items.length
  end
end