DSA C#

📚 Stack Implementation in C# (Using Array)

This example demonstrates how to implement a Stack Data Structure in C# using an array, covering all basic operations like Push, Pop, Peek, and Print.


🧱 What is a Stack?

A Stack is a linear data structure that follows the LIFO (Last In First Out) principle.

👉 Example:
Stack of plates 🍽️

  • Last plate added → First removed


⚙️ Stack Class Overview

int[] items;
int top;
int maxSize;

📌 Explanation

  • items → Array to store stack elements

  • top → Tracks the top element index

  • maxSize → Maximum capacity of stack


🏗️ Constructor

public Stack(int size)
{
    maxSize = size;
    items = new int[maxSize];
    top = -1; // Stack is empty
}

📌 Key Points

  • Initializes stack with given size

  • top = -1 → Indicates empty stack


➕ Push Operation

public void Push(int num)
{
    if(top == maxSize - 1)
    {
        Console.WriteLine("Stack Overflow");
        return;
    }
    items[++top] = num;
}

📌 Logic

  • Checks if stack is full

  • Increments top

  • Inserts element


➖ Pop Operation

public int Pop()
{
    if(IsEmpty())
    {
        Console.WriteLine("Stack is Empty");
        return -1;
    }
    return items[top--];
}

📌 Logic

  • Checks if stack is empty

  • Returns top element

  • Decrements top


👀 Peek Operation

public int Peek()
{
    if (IsEmpty())
    {
        Console.WriteLine("Stack is empty!");
        return -1;
    }
    return items[top];
}

📌 Logic

  • Returns top element without removing it


🖨️ Print Stack

public void PrintStack()
{
    if(IsEmpty())
    {
        Console.WriteLine("Stack is Empty");
        return;
    }
    Console.WriteLine("Printing");
    for(int i = top;i >= 0; i--)
    {
        Console.WriteLine(items[i]);
    }
}

⚠️ Important Note

  • Loop condition:

    for(int i = top; i >= top; i--)
    

    👉 This will print only the top element, not the full stack.

  • Ideally, it should be:

    for(int i = top; i >= 0; i--)
    

🔍 IsEmpty Method

public bool IsEmpty()
{
    return top == -1;
}

📌 Logic

  • If top == -1 → Stack is empty


🚀 Main Method Execution

Stack stack = new Stack(5);

stack.Push(10);
stack.Push(20);
stack.Push(30);

stack.PrintStack();

stack.Peek();

stack.Pop();

stack.PrintStack();

📤 Execution Flow

  1. Push elements → 10, 20, 30

  2. Print → Shows top element (due to loop issue)

  3. Peek → Returns 30

  4. Pop → Removes 30

  5. Print again → Shows new top


🧠 Key Takeaways

  • Stack follows LIFO principle

  • Push, Pop, Peek are core operations

  • Always handle:

    • Overflow (full stack)

    • Underflow (empty stack)

  • Be careful with loop conditions while printing


📌 Summary

  • Implemented stack using array

  • Managed top pointer manually

  • Demonstrated core stack operations

  • Highlighted a common bug in traversal logic


📚 Queue Implementation in C# (Using Circular Array)

This example demonstrates how to implement a Queue Data Structure in C# using an array with circular queue logic, covering operations like Enqueue, Dequeue, and Print.


🧱 What is a Queue?

A Queue is a linear data structure that follows the FIFO (First In First Out) principle.

👉 Example:
Queue at a ticket counter 🎟️

  • First person enters → First person served


⚙️ Queue Class Overview

public int[] items;
public int front;
public int rear;
public int count;
public int maxSize;

📌 Explanation

  • items → Array to store queue elements

  • front → Points to the first element

  • rear → Points to the last element

  • count → Number of elements in queue

  • maxSize → Maximum capacity


🏗️ Constructor

public Queue(int size)
{
    maxSize = size;
    items = new int[maxSize];
    front = 0;
    rear = -1;
    count = 0;
}

📌 Key Points

  • Initializes queue with given size

  • front = 0 → Start of queue

  • rear = -1 → No element initially

  • count = 0 → Queue is empty


➕ Enqueue Operation

public void Enqueue(int num)
{
    if(count == maxSize)
    {
        Console.WriteLine("Queue is Overflow");
        return;
    }
    rear = (rear + 1) % maxSize;
    items[rear] = num;
    count++;
}

📌 Logic

  • Checks if queue is full (overflow)

  • Uses circular increment:

    rear = (rear + 1) % maxSize;
    
  • Adds element at rear

  • Increases count


➖ Dequeue Operation

public void Dequeue()
{
    if(IsEmpty())
    {
        Console.WriteLine("Queue is Empty");
        return;
    }
    int removedItem = items[front];
    front = (front + 1) % maxSize;
    count--;
}

📌 Logic

  • Checks if queue is empty (underflow)

  • Removes element from front

  • Moves front forward using circular logic

  • Decreases count


🔍 Check if Queue is Empty

public bool IsEmpty()
{
    return count == 0;
}

🖨️ Print Queue

public void PrintQueue()
{
    if(IsEmpty())
    {
        Console.WriteLine("Queue is Empty");
        return;
    }
    for(int i=0; i<count; i++)
    {
        int index = (front + i) % maxSize;
        Console.WriteLine(items[index]);
    }
}

📌 Logic

  • Iterates count times

  • Uses circular indexing:

    index = (front + i) % maxSize;
    
  • Ensures correct order even after wrap-around


🚀 Main Method Execution

Queue queue = new Queue(6);

queue.Enqueue(10);
queue.Enqueue(20);
queue.Enqueue(30);
queue.Enqueue(40);
queue.Enqueue(50);
queue.Enqueue(60);

queue.PrintQueue();

queue.Dequeue();

queue.PrintQueue();

queue.Enqueue(60);

queue.PrintQueue();

📤 Execution Flow

  1. Insert elements → 10, 20, 30, 40, 50, 60

  2. Print → Displays all elements

  3. Dequeue → Removes 10

  4. Print → 20, 30, 40, 50, 60

  5. Enqueue 60 again → Circular insertion

  6. Print → Updated queue with wrap-around


🧠 Key Takeaways

  • Queue follows FIFO principle

  • Circular queue avoids wasted space

  • Important operations:

    • Enqueue → Insert

    • Dequeue → Remove

  • Always handle:

    • Overflow (queue full)

    • Underflow (queue empty)

  • Modulo % operator is key for circular behavior


📌 Summary

  • Implemented queue using array + circular logic

  • Efficient memory usage compared to linear queue

  • Demonstrates real-world queue behavior


📌 Singly Linked List in C# (CRUD Operations)

Linked List is a linear data structure where elements (nodes) are stored in memory non-contiguously, and each node points to the next node.

In this implementation, we cover all basic CRUD operations:

  • ✅ Create (Add Node)

  • 🔍 Read (Search & Print)

  • ✏️ Update

  • ❌ Delete


🧱 Node Structure

Each node contains:

  • Data → the value

  • Next → reference to the next node

using System;

public class Node
{
    public int Data;
    public Node Next;
    
    public Node(int data)
    {
       Data = data;
       Next = null;
    }
}

🔗 Singly Linked List Implementation

We use a static class with a head pointer to manage the list.


➕ Add Node (Create)

Adds a new node at the end of the list.

public static class SinglyLinkedList
{
  public static Node head;

  public static void AddNode(int num)
  {
      Node newNode = new Node(num);
      if(head == null)
      {
          head = newNode;
          return;
      }
      
      Node currentNode = head;
      while(currentNode.Next != null)
      {
          currentNode = currentNode.Next;
      }
      currentNode.Next = newNode;
  }

❌ Delete Node

Deletes the first occurrence of a given value.

  public static void DeleteNode(int num)
  {
    if(head == null)
    {
        return;
    }
    if(head.Data == num)
    {
        head = head.Next;
    }
    Node current = head;
    while(current.Next != null && current.Next.Data != num)
    {
        current = current.Next;
    }
    if (current.Next != null)
    {
        current.Next = current.Next.Next;
    }
  }

🔍 Search Node (Read)

Checks whether a value exists in the list.

  public static bool SearchNode(int num)
  {
   if(head == null)
   {
       return false;
   }
   if(head.Data == num)
   {
       return true;
   }
   Node current = head;
   while(current != null)
   {
       if(current.Data == num)
       {
       return true;
       }
       current = current.Next;
   }

   return false;
  }

🖨️ Print Nodes (Read)

Traverses and prints all elements in the list.

  public static void PrintNode()
  {
    Node current = head;
    while(current != null)
    {
        Console.WriteLine(current.Data);
        current = current.Next;
    }
  }

✏️ Update Node

Updates the first occurrence of a given value.

  public static void UpdateNode(int oldNum, int newNum)
  {
   if(head == null)
   {
       return;
   }
   if(head.Data == oldNum)
   {
       head.Data = newNum;
   }
   Node current = head;
   bool isFound = false;
   while(current.Next != null)
   {
       if(current.Data == oldNum)
       {
          current.Data = newNum;
          isFound = true;
          break;
       }
       current = current.Next;
   }
   
   if(!isFound)
   {
      Console.WriteLine("Not Found the number to update");
   }
  }
}

🚀 Execution Example

public class HelloWorld
{
    public static void Main(string[] args)
    {
       SinglyLinkedList.AddNode(10);
       SinglyLinkedList.AddNode(20);
       SinglyLinkedList.AddNode(30);
       
       Console.WriteLine("==========Before Deletion============");
       SinglyLinkedList.PrintNode();
       
       SinglyLinkedList.DeleteNode(20);
       Console.WriteLine("=========After Deletion==============");
       SinglyLinkedList.PrintNode();
        
       Console.WriteLine("=========Searching==============");
       bool valueExists = SinglyLinkedList.SearchNode(20);
       Console.WriteLine(valueExists);
       
       SinglyLinkedList.UpdateNode(30,20);
       Console.WriteLine("=========Updating==============");
       SinglyLinkedList.PrintNode();
       
       Console.WriteLine("=========Searching==============");
       bool valueExists2 = SinglyLinkedList.SearchNode(20);
       Console.WriteLine(valueExists2);
    }
}

🧠 Key Takeaways

  • Linked Lists are dynamic and efficient for insertions/deletions.

  • Traversal is required for most operations → O(n) complexity.

  • No index-based access like arrays.

  • Useful in scenarios where memory flexibility is needed.

Comments