Data Structures Tutorial

Data Structures Tutorial Asymptotic Notation Structure and Union Array Data Structure Linked list Data Structure Type of Linked list Advantages and Disadvantages of linked list Queue Data Structure Implementation of Queue Stack Data Structure Implementation of Stack Sorting Insertion sort Quick sort Selection sort Heap sort Merge sort Bucket sort Count sort Radix sort Shell sort Tree Traversal of the binary tree Binary search tree Graph Spanning tree Linear Search Binary Search Hashing Collision Resolution Techniques

Misc Topic:

Priority Queue in Data Structure Deque in Data Structure Difference Between Linear And Non Linear Data Structures Queue Operations In Data Structure About Data Structures Data Structures Algorithms Types of Data Structures Big O Notations Introduction to Arrays Introduction to 1D-Arrays Operations on 1D-Arrays Introduction to 2D-Arrays Operations on 2D-Arrays Strings in Data Structures String Operations Application of 2D array Bubble Sort Insertion Sort Sorting Algorithms What is DFS Algorithm What Is Graph Data Structure What is the difference between Tree and Graph What is the difference between DFS and BFS Bucket Sort Dijkstra’s vs Bellman-Ford Algorithm Linear Queue Data Structure in C Stack Using Array Stack Using Linked List Recursion in Fibonacci Stack vs Array What is Skewed Binary Tree Primitive Data Structure in C Dynamic memory allocation of structure in C Application of Stack in Data Structures Binary Tree in Data Structures Heap Data Structure Recursion - Factorial and Fibonacci What is B tree what is B+ tree Huffman tree in Data Structures Insertion Sort vs Bubble Sort Adding one to the number represented an array of digits Bitwise Operators and their Important Tricks Blowfish algorithm Bubble Sort vs Selection Sort Hashing and its Applications Heap Sort vs Merge Sort Insertion Sort vs Selection Sort Merge Conflicts and ways to handle them Difference between Stack and Queue AVL tree in data structure c++ Bubble sort algorithm using Javascript Buffer overflow attack with examples Find out the area between two concentric circles Lowest common ancestor in a binary search tree Number of visible boxes putting one inside another Program to calculate the area of the circumcircle of an equilateral triangle Red-black Tree in Data Structures Strictly binary tree in Data Structures 2-3 Trees and Basic Operations on them Asynchronous advantage actor-critic (A3C) Algorithm Bubble Sort vs Heap Sort Digital Search Tree in Data Structures Minimum Spanning Tree Permutation Sort or Bogo Sort Quick Sort vs Merge Sort Boruvkas algorithm Bubble Sort vs Quick Sort Common Operations on various Data Structures Detect and Remove Loop in a Linked List How to Start Learning DSA Print kth least significant bit number Why is Binary Heap Preferred over BST for Priority Queue Bin Packing Problem Binary Tree Inorder Traversal Burning binary tree Equal Sum What is a Threaded Binary Tree? What is a full Binary Tree? Bubble Sort vs Merge Sort B+ Tree Program in Q language Deletion Operation from A B Tree Deletion Operation of the binary search tree in C++ language Does Overloading Work with Inheritance Balanced Binary Tree Binary tree deletion Binary tree insertion Cocktail Sort Comb Sort FIFO approach Operations of B Tree in C++ Language Recaman’s Sequence Tim Sort Understanding Data Processing Applications of trees in data structures Binary Tree Implementation Using Arrays Convert a Binary Tree into a Binary Search Tree Create a binary search tree Horizontal and Vertical Scaling Invert binary tree LCA of binary tree Linked List Representation of Binary Tree Optimal binary search tree in DSA Serialize and Deserialize a Binary Tree Tree terminology in Data structures Vertical Order Traversal of Binary Tree What is a Height-Balanced Tree in Data Structure Convert binary tree to a doubly linked list Fundamental of Algorithms Introduction and Implementation of Bloom Filter Optimal binary search tree using dynamic programming Right side view of binary tree Symmetric binary tree Trim a binary search tree What is a Sparse Matrix in Data Structure What is a Tree in Terms of a Graph What is the Use of Segment Trees in Data Structure What Should We Learn First Trees or Graphs in Data Structures All About Minimum Cost Spanning Trees in Data Structure Convert Binary Tree into a Threaded Binary Tree Difference between Structured and Object-Oriented Analysis FLEX (Fast Lexical Analyzer Generator) Object-Oriented Analysis and Design Sum of Nodes in a Binary Tree What are the types of Trees in Data Structure What is a 2-3 Tree in Data Structure What is a Spanning Tree in Data Structure What is an AVL Tree in Data Structure Given a Binary Tree, Check if it's balanced B Tree in Data Structure Convert Sorted List to Binary Search Tree Flattening a Linked List Given a Perfect Binary Tree, Reverse Alternate Levels Left View of Binary Tree What are Forest Trees in Data Structure Compare Balanced Binary Tree and Complete Binary Tree Diameter of a Binary Tree Given a Binary Tree Check the Zig Zag Traversal Given a Binary Tree Print the Shortest Path Given a Binary Tree Return All Root To Leaf Paths Given a Binary Tree Swap Nodes at K Height Given a Binary Tree Find Its Minimum Depth Given a Binary Tree Print the Pre Order Traversal in Recursive Given a Generate all Structurally Unique Binary Search Trees Perfect Binary Tree Threaded Binary Trees Function to Create a Copy of Binary Search Tree Function to Delete a Leaf Node from a Binary Tree Function to Insert a Node in a Binary Search Tree Given Two Binary Trees, Check if it is Symmetric A Full Binary Tree with n Nodes Applications of Different Linked Lists in Data Structure B+ Tree in Data Structure Construction of B tree in Data Structure Difference between B-tree and Binary Tree Finding Rank in a Binary Search Tree Finding the Maximum Element in a Binary Tree Finding the Minimum and Maximum Value of a Binary Tree Finding the Sum of All Paths in a Binary Tree Time Complexity of Selection Sort in Data Structure How to get Better in Data Structures and Algorithms Binary Tree Leaf Nodes Classification of Data Structure Difference between Static and Dynamic Data Structure Find the Union and Intersection of the Binary Search Tree Find the Vertical Next in a Binary Tree Finding a Deadlock in a Binary Search Tree Finding all Node of k Distance in a Binary Tree Finding Diagonal Sum in a Binary Tree Finding Diagonal Traversal of The Binary Tree Finding In-Order Successor Binary Tree Finding the gcd of Each Sibling of the Binary Tree Greedy Algorithm in Data Structure How to Calculate Space Complexity in Data Structure How to find missing numbers in an Array Kth Ancestor Node of Binary Tree Minimum Depth Binary Tree Mirror Binary Tree in Data Structure Red-Black Tree Insertion Binary Tree to Mirror Image in Data Structure Calculating the Height of a Binary Search Tree in Data Structure Characteristics of Binary Tree in Data Structure Create a Complete Binary Tree from its Linked List Field in Tree Data Structure Find a Specified Element in a binary Search Tree Find Descendant in Tree Data Structure Find Siblings in a Binary Tree Given as an Array Find the Height of a Node in a Binary Tree Find the Second-Largest Element in a Binary Tree Find the Successor Predecessor of a Binary Search Tree Forest of a Tree in Data Structure In Order Traversal of Threaded Binary Tree Introduction to Huffman Coding Limitations of a Binary Search Tree Link State Routing Algorithm in Data Structure Map Reduce Algorithm for Binary Search Tree in Data Structure Non-Binary Tree in Data Structure Quadratic Probing Example in Hashing Scope and Lifetime of Variables in Data Structure Separate Chaining in Data Structure What is Dynamic Data Structure Separate Chaining vs Open Addressing Time and Space Complexity of Linear Data Structures Abstract Data Types in Data Structures Binary Tree to Single Linked List Count the Number of Nodes in the Binary Tree Count Total No. of Ancestors in a Binary Search Tree Elements of Dynamic Programming in Data Structures Find cost of tree with prims algorithm in data structures Find Preorder Successor in a Threaded Binary Tree Find Prime Nodes Sum Count in Non-Binary Tree Find the Right Sibling of a Binary Tree with Parent Pointers Find the Width of the Binary Search Tree Forest trees in Data Structures Free Tree in Data Structures Frequently asked questions in Tree Data Structures Infix, Postfix and Prefix Conversion Time Complexity of Fibonacci Series What is Weighted Graph in Data Structure

Introduction to Data Structures Stack and Queue with Example Code in C++

Data structures are fundamental concepts in computer science and programming. They allow programmers to organize, store and efficiently manipulate data. Two commonly used data structures are stack and queue. In this article, we will introduce the basic concepts of stack and queue and provide example code in C++.

Stack

A stack is a data structure that follows the Last In, First Out (LIFO) principle. It can be visualized as a stack of plates where the last plate added to the stack is the first plate to be removed. The operations performed on a stack are:

  • Push: Add an element to the top of the stack

Algorithm for push

begin
 if the stack is full
    return
 endif
else  
 increment top
 stack[top] assign value
end else
end procedure
  • Pop: Remove the top element from the stack

Algorithm for pop

begin
 if the stack is empty
    return
 endif
else
 store value of stack[top]
 decrement top
 return value
end else
end procedure
  • Top: Retrieve the top element from the stack without removing it.

Algorithm for top

begin 
  return stack[top]
end procedure
  • isEmpty: Check if the stack is empty

algorithm for isEmpty

begin
 if top < 1
    return true
 else
    return false
end procedure

Applications of Stack

Stacks have many applications in computer science and programming. Here are some of the common applications of the stack:

  • Expression evaluation: Stacks are used to evaluating expressions in programming languages. For example, postfix notation can be used along with a stack to evaluate arithmetic expressions.
  • Function calls and recursion: Stacks are used to keeping track of function calls and recursive calls. When a function is called, its local variables and return addresses are stored on the stack, and when the function returns, the values are popped up from the stack.
  • Backtracking: Stacks are used to implementing backtracking algorithms such as depth-first search. In such algorithms, the states of the search are pushed onto the stack, and when a dead-end is reached, the states are popped, and the search continues from the previous state.
  • Parsing: Stacks are used to parsing and validate the syntax of programming languages. Each token is pushed onto the stack in a parser, and when a syntax rule is matched, the tokens are popped from the stack.
  • Memory management: Stacks are used in memory management, such as allocating and deallocating memory on the heap.
  • Undo/Redo: Stacks are used to implement the undo and redo functionality in many applications, such as text editors, where the most recent action is stored on the stack and can be undone by popping it from the stack.

Complexity analysis

Time complexity

  operations  complexity
  Push()   0(1)
  Pop()   0(1)
  IsEmpty()   0(1)
  Size()   0(1)

Here is an example implementation of a stack data structure in C++ using a dynamic array:

#include <iostream>
using namespace std;


class Stack {
private:
    int* data;  // pointer to dynamic array to store elements
    int capacity;  // maximum number of elements in the stack
    int topIndex;  // index of the top element
public:
    Stack(int cap) {
        capacity = cap;
        data = new int[capacity];
        topIndex = -1;  // initialize the top index to -1 to indicate an empty stack
    }
    
    ~Stack() {
        delete[] data;  // deallocate the dynamic array
    }
    
    void push(int val) {
        if (topIndex == capacity - 1) {
            cout << "Stack overflow" << endl;
            return;
        }
        topIndex++;
        data[topIndex] = val;
    }
    
    void pop() {
        if (topIndex == -1) {
            cout << "Stack underflow" << endl;
            return;
        }
        topIndex--;
    }
    
    int top() {
        if (topIndex == -1) {
            cout << "Stack is empty" << endl;
            return -1;
        }
        return data[topIndex];
    }
    
    bool isEmpty() {
        return (topIndex == -1);
    }
};


int main() {
    Stack myStack(5);  // create a stack with capacity 5
    
    myStack.push(1);
    myStack.push(2);
    myStack.push(3);
    cout << "Top element: " << myStack.top() << endl;
    myStack.pop();
    cout << "Top element: " << myStack.top() << endl;
    myStack.push(4);
    myStack.push(5);
    myStack.push(6);  // should cause stack overflow error
    while (!myStack.isEmpty()) {
        cout << myStack.top() << " ";
        myStack.pop();
    }
    cout << endl;
    
    return 0;
}

Output :

Introduction to Data Structures: Stack and Queue with Example Code in C++

This implementation defines a Stack class with a dynamic array to store the elements, the maximum capacity, the index of the top element, and four basic operations: push, pop, top, and isEmpty.

In Summarized way:

  • The push operation adds an element to the top of the stack, and if the stack is already full, it prints an error message.
  • The pop operation removes the top element from the stack; if the stack is empty, it prints an error message.
  • The top operation returns the top element of the stack without removing it, and if the stack is already empty, it prints an error message.
  • The isEmpty operation returns true if the stack is empty and false otherwise.

The main function demonstrates the usage of the Stack class by creating a stack, pushing, and popping elements, and printing the elements in reverse order.

Here is an example implementation of a stack data structure in C++ using a linked list:

#include <iostream>
using namespace std;


class Node {
public:
    int val;  // value of the node
    Node* next;  // pointer to the next node
};


class Stack {
private:
    Node* head;  // pointer to the head node of the linked list
public:
    Stack() {
        head = NULL;  // initialize the head pointer to NULL to indicate an empty list
    }
    
    ~Stack() {
        while (head != NULL) {  // deallocate all the nodes in the linked list
            Node* temp = head;
            head = head->next;
            delete temp;
        }
    }
    
    void push(int val) {
        Node* newNode = new Node;  // create a new node
        newNode->val = val;
        newNode->next = head;
        head = newNode;  // update the head pointer to point to the new node
    }
    
    void pop() {
        if (head == NULL) {
            cout << "Stack underflow" << endl;
            return;
        }
        Node* temp = head;
        head = head->next;
        delete temp;  // deallocate the node being removed
    }
    
    int top() {
        if (head == NULL) {
            cout << "Stack is empty" << endl;
            return -1;
        }
        return head->val;
    }
    
    bool isEmpty() {
        return (head == NULL);
    }
};


int main() {
    Stack myStack;
    
    myStack.push(1);
    myStack.push(2);
    myStack.push(3);
    cout << "Top element: " << myStack.top() << endl;
    myStack.pop();
    cout << "Top element: " << myStack.top() << endl;
    myStack.push(4);
    myStack.push(5);
    myStack.push(6);
    while (!myStack.isEmpty()) {
        cout << myStack.top() << " ";
        myStack.pop();
    }
    cout << endl;
    
    return 0;
}

Output:

Top element: 3
Top element: 2
6 5 4 2 1

Queue

A queue is a data structure that follows the First In First Out (FIFO) principle. It can be visualized as a queue of people waiting in line where the first person who joins the line is the first person to be served. The operations performed on a queue are:

  • Enqueue: Add an element to the back of the queue
  • Dequeue: Remove the front element from the queue
  • Front: Retrieve the front element from the queue without removing it
  • Empty: Check if the queue is empty

Complexity analysis

OperationsComplexity
Enqueue(insertion)0(1)
Dqueue(deletion)0(1)
Front(get front)0(1)
Rear(get rear)0(1)
Isfull(check queue is full or not)0(1)
Isempty(check queue is empty or not)0()

The basic implementation of a queue is using an array. Here is an example code using an array in C++:

Here is an example implementation of a queue data structure in C++ using an array:

#include <iostream>
using namespace std;


const int MAXN = 100;  // maximum size of the queue


class Queue {
private:
    int q[MAXN];  // array to store the elements of the queue
    int front;  // index of the front element
    int rear;  // index of the rear element
public:
    Queue() {
        front = -1;
        rear = -1;  // initialize both front and rear to -1 to indicate an empty queue
    }
    
    bool isEmpty() {
        return (front == -1 && rear == -1);  // the queue is empty if both front and rear are -1
    }
    
    bool isFull() {
        return (rear == MAXN - 1);  // the queue is full if rear has reached the maximum index
    }
    
    void enqueue(int val) {
        if (isFull()) {
            cout << "Queue overflow" << endl;
            return;
        }
        if (isEmpty()) {
            front = 0;  // if the queue is empty, set both front and rear to 0
        }
        rear++;
        q[rear] = val;  // insert the element at the rear of the queue
    }
    
    void dequeue() {
        if (isEmpty()) {
            cout << "Queue underflow" << endl;
            return;
        }
        if (front == rear) {
            front = -1;
            rear = -1;  // if the queue has only one element, set both front and rear to -1 to indicate an empty queue
        }
        else {
            front++;  // increment the front index to remove the front element
        }
    }
    
    int getFront() {
        if (isEmpty()) {
            cout << "Queue is empty" << endl;
            return -1;
        }
        return q[front];  // return the value of the front element
    }
};


int main() {
    Queue myQueue;
    
    myQueue.enqueue(1);
    myQueue.enqueue(2);
    myQueue.enqueue(3);
    cout << "Front element: " << myQueue.getFront() << endl;
    myQueue.dequeue();
    cout << "Front element: " << myQueue.getFront() << endl;
    myQueue.enqueue(4);
    myQueue.enqueue(5);
    myQueue.enqueue(6);
    while (!myQueue.isEmpty()) {
        cout << myQueue.getFront() << " ";
        myQueue.dequeue();
    }
    cout << endl;
    
    return 0;
}

Explanation:

This implementation defines a Queue class that has an array to store the elements of the queue, and two indices front and rear to keep track of the front and rear elements of the queue.

  • The isEmpty operation returns true if both front and rear are -1, indicating an empty queue.
  • The isFull operation returns true if the rear has reached the maximum index, indicating a full queue.
  • The enqueue operation inserts an element at the rear of the queue by incrementing the rear index and inserting the element at the new rear position. It also checks for an overflow condition.
  • The dequeue operation removes the element at the front of the queue by incrementing the front index and checking for underflow conditions. If the queue has only one element, it sets both front and rear to -1 to indicate an empty queue.
  • The getFront operation returns the value of the front element of the queue, and if the queue is empty, it prints an error message.

The main function demonstrates the usage of the Queue class by creating a queue, enqueueing and dequeuing elements, and printing the front element of the queue.

Output:

Introduction to Data Structures: Stack and Queue with Example Code in C++

In this example, we created a Queue object named queue. We enqueue the elements 1, 2, and 3 and print the front element of the queue, which is 1. We then dequeue the front element, which is 1, and print the new front element, which is 2. We enqueued elements 4, 5, and 6, but when we try to enqueue element 7, we get an overflow error message because the queue is full. We then dequeue all the elements from the queue and print them, which gives us the output 2 3 4 5 6. Finally, we check if the queue is empty by calling the isEmpty operation, which returns true

Types of Queue

Here's a brief overview of each type of queue:

  • Single Queue: A single queue is a basic data structure following the First-In-First-Out (FIFO) principle. Elements are inserted from the rear end and deleted from the front end. Single queues can be implemented using arrays or linked lists.
  • Circular Queue: A circular queue is a modified version of the linear queue in which the last element points to the first element, making a circular link. In a circular queue, elements are added to the rear end and deleted from the front end. Circular queues can be implemented using arrays or linked lists.
  • Priority Queue: A priority queue is a type of queue in which each element is assigned a priority and is inserted in the queue according to its priority. The element with the highest priority is placed at the front of the queue, and the element with the lowest priority is placed at the rear of the queue. Priority queues can be implemented using a variety of data structures such as arrays, linked lists, binary heaps, and balanced binary search trees.
  • Deque: A deque, short for the double-ended queue, is a data structure that allows elements to be inserted and deleted from both ends. A deque can be considered a combination of a stack and a queue. It supports operations such as push_front, push_back, pop_front, pop_back, front, and back. Deques can be implemented using arrays or linked lists.

Conclusion: Stack and queue data structures are important concepts in computer science and programming, and understanding their basic principles and implementations is essential for building efficient algorithms and software. Stack and queue are commonly used data structures that follow different principles, but both are useful in various applications.