0% found this document useful (0 votes)
1 views

Ultimate Data Structures Notes

The document provides comprehensive notes on data structures, covering prerequisites such as functions, recursion, arrays, pointers, and structures. It introduces key concepts of data structures, including types, operations, and specific structures like stacks, queues, linked lists, and trees. Additionally, it discusses the importance of data structures in programming and includes oral exam questions for each section.

Uploaded by

thangenabil44
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views

Ultimate Data Structures Notes

The document provides comprehensive notes on data structures, covering prerequisites such as functions, recursion, arrays, pointers, and structures. It introduces key concepts of data structures, including types, operations, and specific structures like stacks, queues, linked lists, and trees. Additionally, it discusses the importance of data structures in programming and includes oral exam questions for each section.

Uploaded by

thangenabil44
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

ULTIMATE DATA STRUCTURES NOTES

📚 TABLE OF CONTENTS
1. Prerequisites
Functions

Recursion
Arrays

Pointers
Structures

2. Introduction to Data Structures


What are Data Structures?

Abstract Data Types (ADT)

Types of Data Structures


Operations on Data Structures

3. Stack
Stack as ADT
Array Implementation of Stack

Multiple Stacks

4. Queue
Queue as ADT
Array Implementation of Queue
Circular Queue
Priority Queue
Double Ended Queue (Deque)

Multiple Queues

5. Linked List
Concept of Linked List vs Array
Singly Linked List
Doubly Linked List

Circular Linked List


Stack Using Linked List

Queue Using Linked List


Reversing a Linked List

6. Tree
Tree Concepts and Terms
Binary Tree

Binary Tree Traversals


Binary Search Tree (BST)

7. Applications of Data Structures


Stack Applications
Trees Applications

8. Summary of Key Concepts

<a id="prerequisites"></a>

0. PREREQUISITES
<a id="functions"></a>

Functions
What are functions?
Functions are blocks of code that perform specific tasks. They help us organize our program into
reusable pieces.

Key Characteristics of Functions:

Reusability: Write once, use many times

Modularity: Break complex programs into manageable pieces


Abstraction: Hide implementation details from the user

Example:

// This function adds two numbers and returns the sum


int add(int a, int b) {
return a + b; // Returns the sum of a and b
}

// This is how you call the function


int result = add(5, 3); // result will be 8

Algorithm Explanation:

1. Function add takes two integer parameters a and b

2. It calculates their sum and returns the result

3. When calling the function with values 5 and 3, it returns 8


<a id="recursion"></a>

Recursion
What is recursion?
When a function calls itself to solve a problem. It breaks a problem into smaller versions of the same
problem.

Key Characteristics of Recursion:

Base Case: A condition that stops the recursion

Recursive Case: The function calls itself with a simpler version of the problem

Call Stack: Each recursive call is added to the call stack

Example: Calculating factorial

// Function to calculate factorial using recursion


int factorial(int n) {
if (n <= 1) { // Base case: factorial of 0 or 1 is 1
return 1;
} else {
return n * factorial(n-1); // Function calls itself with smaller value
}
}

// Usage: factorial(5) = 5 * 4 * 3 * 2 * 1 = 120

Algorithm Explanation:

1. Check if n is 0 or 1 (base case)


2. If true, return 1 (factorial of 0 or 1 is 1)

3. Otherwise, return n * factorial(n-1) (recursive case)

4. For factorial(5):
factorial(5) = 5 * factorial(4)

factorial(4) = 4 * factorial(3)

factorial(3) = 3 * factorial(2)

factorial(2) = 2 * factorial(1)

factorial(1) = 1 (base case reached)

Then unwind: 21 = 2, 32 = 6, 46 = 24, 524 = 120

<a id="arrays"></a>

Arrays
What are arrays?
Collections of similar data items stored at contiguous memory locations.

Key Characteristics of Arrays:

Fixed Size: Size is defined at declaration

Homogeneous Elements: All elements must be of the same data type

Random Access: Can access any element directly using its index

Zero-based Indexing: First element is at index 0

Example:
c

// Declaring and initializing an array


int marks[5] = {85, 75, 90, 67, 82}; // Array of 5 integers

// Accessing array elements


printf("First mark: %d\n", marks[0]); // Arrays start at index 0
printf("Third mark: %d\n", marks[2]); // Access the third element

// Modifying array elements


marks[1] = 95; // Change the second element to 95

Algorithm for Array Operations:

1. Declaration: Allocate contiguous memory for fixed number of elements

2. Access: Calculate address using base address + (index * size of data type)

3. Modification: Direct access to memory location to change value

<a id="pointers"></a>

Pointers (Basic Introduction)


What are pointers?
Variables that store memory addresses of other variables.

Key Characteristics of Pointers:

Address Storage: Store memory addresses, not actual values


Indirection: Access values indirectly through memory addresses

Dynamic Memory: Enable dynamic memory allocation and deallocation

Efficient Parameter Passing: Pass references instead of copying large data


Simple Example:

int number = 10; // Regular integer variable


int *ptr = &number; // Pointer storing address of 'number'

printf("Value: %d\n", number); // Prints: 10


printf("Value using pointer: %d\n", *ptr); // Prints: 10 (dereferencing)

Algorithm for Pointer Operations:

1. Declaration: Create a pointer variable of specific type

2. Assignment: Store address of a variable using & operator

3. Dereferencing: Access value at the address using * operator

<a id="structures"></a>

Structures
What are structures?
User-defined data types that allow storing different types of data items together.

Key Characteristics of Structures:

Heterogeneous Elements: Can store different data types together

Related Data Grouping: Group related data under a single name

Memory Allocation: Contiguous memory allocation for all members

Member Access: Use dot (.) operator to access members

Example:
c

// Define a structure for a student


struct Student {
char name[50]; // Character array for name
int roll_no; // Integer for roll number
float marks; // Float for marks
};

// Creating and using a structure variable


struct Student s1 = {"Alice", 101, 85.5}; // Initialize all members

printf("Name: %s\n", s1.name); // Access using dot operator


printf("Roll No: %d\n", s1.roll_no);

Algorithm for Structure Operations:

1. Definition: Define structure template with members of different types

2. Declaration: Create variables of the structure type

3. Initialization: Assign values to structure members


4. Access: Use dot operator to access individual members

📝 Prerequisites: Oral Exam Questions


1. Functions
What are functions and why are they important in programming?
Explain the difference between function declaration and function definition.

What is the purpose of the return statement in a function?


What is function overloading? Does C support it?
What are the advantages of using functions in a program?

2. Recursion
What is recursion and how does it differ from iteration?
What are the essential components of a recursive function?

What are the advantages and disadvantages of recursion?


Explain how the factorial function works recursively.

How does the call stack work during recursive function calls?

What is stack overflow in the context of recursion?

3. Arrays
What is an array? How is memory allocated for arrays?
Why is index 0 used for the first element in an array?

What are the limitations of arrays in C?

How are multi-dimensional arrays stored in memory?

What is the difference between declaration and initialization of an array?

4. Pointers
What is a pointer and what does it contain?

What is the difference between & and * operators regarding pointers?


What is dereferencing? How do you dereference a pointer?

Why are pointers useful in C programming?

What is a null pointer and when would you use it?

5. Structures
What is a structure in C? How does it differ from an array?
How do you access members of a structure?
Can structures contain other structures? Explain.

What is the difference between a structure and a union?

Why would you use structures in a program?

<a id="introduction"></a>

I. INTRODUCTION
<a id="what-are-data-structures"></a>

What are Data Structures?


Definition: Data structures are specialized formats for organizing, processing, retrieving and storing
data in a computer.

Think of it like: If data is like items, then data structures are like different types of containers to store
these items - each with its own way of adding, removing, and accessing items.

Importance of Data Structures:

Efficiency: Proper data structures can make algorithms more efficient


Organization: Help organize and manage large amounts of data

Problem Solving: Different problems require different data organization techniques

Memory Utilization: Optimize memory usage for specific applications

<a id="abstract-data-types-adt"></a>

Abstract Data Types (ADT)


Definition: An ADT is a mathematical model for data structures, defined by its behavior from the
user's perspective.
Real-life example: Think of a TV remote. You know what buttons do what functions (interface), but
you don't need to know the electronic circuitry inside (implementation) to use it.

Key Characteristics of ADTs:

Abstraction: Hide implementation details from the user

Operations: Define operations that can be performed


Data: Define the data to be stored

Interface: Provide clear interface for interactions

Common ADTs include:

Stack (Last-In-First-Out)
Queue (First-In-First-Out)

List
Tree

<a id="types-of-data-structures"></a>

Types of Data Structures

1. Linear vs Nonlinear:

Linear: Elements form a sequence


Arrays, Linked Lists, Stacks, Queues

Each element has at most one predecessor and one successor


Elements can be traversed sequentially

Nonlinear: Elements don't form a sequence


Trees, Graphs
Elements can have multiple predecessors and successors
Multiple paths between elements

2. Static vs Dynamic:

Static: Fixed size, allocated at compile time


Arrays

Size cannot be changed during execution

Memory allocated once

Dynamic: Size can change during program execution


Linked Lists, Dynamic Arrays

Can grow or shrink as needed

Memory allocated and deallocated during runtime

3. Primitive vs Non-Primitive:

Primitive: Basic data types built into a language


Integer, Float, Character, Boolean

Directly operated upon by machine instructions

Non-Primitive: Derived from primitive data types


Arrays, Lists, Stacks, Queues, Trees, Graphs
More complex operations and structures

<a id="operations-on-data-structures"></a>

Operations on Data Structures


Common operations include:
Insertion: Adding a new element
Can be at the beginning, end, or specific position

May require reorganization of existing elements

Deletion: Removing an element


Can be from beginning, end, or specific position
May require reorganization of remaining elements

Traversal: Accessing each element exactly once


Sequential visit of all elements
Used for operations like printing, searching, etc.

Searching: Finding a specific element


Linear search, binary search, etc.

Efficiency depends on data structure organization

Sorting: Arranging elements in a particular order


Ascending, descending, or custom order

Various algorithms like bubble sort, quick sort, etc.

Merging: Combining two or more data structures

Splitting: Dividing a data structure into parts

📝 Introduction to Data Structures: Oral Exam Questions


1. What are data structures and why are they important in computer science?
2. Differentiate between data structures and abstract data types.

3. Give real-world examples for abstract data types.


4. What is the difference between linear and non-linear data structures? Give examples of each.
5. Explain the difference between static and dynamic data structures with examples.

6. What factors should be considered when choosing a data structure for a specific problem?

7. How does memory allocation differ between static and dynamic data structures?
8. Describe the common operations that can be performed on data structures.

9. What is traversal and why is it important in data structures?


10. How do primitive data structures differ from non-primitive data structures?
11. What is the relationship between algorithms and data structures?

12. Explain how efficiency of operations varies across different data structures.

<a id="stack"></a>

II. STACK
<a id="stack-as-adt"></a>

Stack as ADT
Definition: A stack is a linear data structure that follows the Last-In-First-Out (LIFO) principle.

Real-life example: Think of a stack of plates. You can only take the top plate (last one placed), not
any from the middle.

Key Principles of Stack:

LIFO (Last-In-First-Out): The last element added is the first one to be removed

Restricted Access: Elements can only be added or removed from one end (top)

Sequential Access: Elements are accessed in reverse order of their addition

Basic Operations:
Push: Add an element to the top

Pop: Remove the top element

Peek/Top: View the top element without removing it

IsEmpty: Check if stack is empty

IsFull: Check if stack is full (for array implementation)

Visual Representation:

│ │
│ C │ ← Top (most recently added)
│ B │
│ A │ ← Bottom (least recently added)
└───────┘

<a id="array-implementation-of-stack"></a>

Array Implementation of Stack


c
#include <stdio.h>
#define MAX 5 // Maximum size of stack

// Global variables
int stack[MAX]; // Array to store the stack elements
int top = -1; // Index of top element, -1 means empty stack

// Function to check if stack is full


int isFull() {
if (top == MAX - 1) { // If top is at the last index
return 1; // Return true (stack is full)
} else {
return 0; // Return false (stack is not full)
}
}

// Function to check if stack is empty


int isEmpty() {
if (top == -1) { // If top is -1
return 1; // Return true (stack is empty)
} else {
return 0; // Return false (stack is not empty)
}
}

// Function to add an element to the stack


void push(int item) {
if (isFull()) { // Check if stack is full
printf("Stack Overflow\n"); // Print error message
} else {
top++; // Increment top
stack[top] = item; // Place the item at top position
printf("%d pushed to stack\n", item);
}
}

// Function to remove an element from the stack


int pop() {
if (isEmpty()) { // Check if stack is empty
printf("Stack Underflow\n"); // Print error message
return -1; // Return error value
} else {
int item = stack[top]; // Get the top item
top--; // Decrement top
return item; // Return the item
}
}

// Function to view the top element without removing it


int peek() {
if (isEmpty()) { // Check if stack is empty
printf("Stack is empty\n"); // Print error message
return -1; // Return error value
} else {
return stack[top]; // Return the top item
}
}

// Sample usage
int main() {
push(10); // Add 10 to stack
push(20); // Add 20 to stack
push(30); // Add 30 to stack
printf("Top element: %d\n", peek()); // Should print 30
printf("Popped: %d\n", pop()); // Should print 30
printf("Popped: %d\n", pop()); // Should print 20
printf("Top element after pops: %d\n", peek()); // Should print 10
return 0;
}

Algorithm Explanation for Stack Operations:

1. Initialization:
Create an array of fixed size (MAX)
Initialize top = -1 (indicating empty stack)

2. isFull() Operation:
Check if top == MAX-1
If true, stack is full, return 1

Otherwise, return 0

3. isEmpty() Operation:
Check if top == -1

If true, stack is empty, return 1


Otherwise, return 0

4. push() Operation:
Check if stack is full using isFull()
If full, print "Stack Overflow"

Otherwise:
Increment top

Place the new item at stack[top]


5. pop() Operation:
Check if stack is empty using isEmpty()

If empty, print "Stack Underflow" and return error value (-1)


Otherwise:
Store the value at stack[top] in a variable
Decrement top
Return the stored value

6. peek() Operation:
Check if stack is empty using isEmpty()

If empty, print "Stack is empty" and return error value (-1)


Otherwise, return the value at stack[top] without changing top

<a id="multiple-stacks"></a>

Multiple Stacks
Multiple stacks can be implemented in a single array by:

1. Dividing the array into fixed sections:


Allocate specific sections of the array for each stack

Each stack has its own top pointer

Simple but less memory efficient if stacks grow unevenly

2. Starting stacks from opposite ends of the array and growing towards the middle:
For two stacks, first stack grows from left to right

Second stack grows from right to left

Stacks are full when they meet in the middle


More efficient use of memory

Visual Representation of Two Stacks in One Array:

[0][1][2][3][4][5][6][7][8][9]
↑ ↑
top1 top2

📝 Stack: Oral Exam Questions


1. What is a stack data structure and what is its fundamental principle?
2. Explain the LIFO (Last-In-First-Out) property with an example.
3. List and explain the basic operations that can be performed on a stack.

4. What are the applications of stack in computer science?


5. What happens when you try to pop an element from an empty stack?

6. What happens when you try to push an element into a full stack?
7. How is a stack implemented using an array? What are the limitations of this implementation?

8. What is the time complexity of push, pop, and peek operations in a stack?
9. What are the advantages and disadvantages of implementing a stack using an array?

10. How can multiple stacks be implemented in a single array?

11. Compare the fixed partition and flexible partition methods for implementing multiple stacks.
12. What is stack overflow and stack underflow? When do they occur?

13. How does the call stack work in programming languages?


14. How is memory managed in a stack implementation?
15. How can a stack be implemented without using an array?
<a id="queue"></a>

III. QUEUE
<a id="queue-as-adt"></a>

Queue as ADT
Definition: A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle.

Real-life example: Think of people standing in line for movie tickets. The person who came first gets
served first.

Key Principles of Queue:

FIFO (First-In-First-Out): The first element added is the first one to be removed

Two Ends: Elements are added at one end (rear) and removed from the other end (front)

Sequential Processing: Processing in the exact order of arrival

Basic Operations:

Enqueue: Add an element to the rear/back


Dequeue: Remove an element from the front

Front: Get the front element without removing


IsEmpty: Check if queue is empty

IsFull: Check if queue is full

Visual Representation:
Front Rear
↓ ↓
[A][B][C][D][ ][ ][ ][ ]

<a id="array-implementation-of-queue"></a>

Array Implementation of Queue


c
#include <stdio.h>
#define MAX 5 // Maximum size of queue

// Global variables
int queue[MAX]; // Array to store queue elements
int front = -1; // Index of front element
int rear = -1; // Index of rear element

// Function to check if queue is full


int isFull() {
if (rear == MAX - 1) { // If rear is at the last index
return 1; // Return true (queue is full)
} else {
return 0; // Return false (queue is not full)
}
}

// Function to check if queue is empty


int isEmpty() {
if (front == -1 || front > rear) { // If front is -1 or has crossed rear
return 1; // Return true (queue is empty)
} else {
return 0; // Return false (queue is not empty)
}
}

// Function to add an element to the queue


void enqueue(int item) {
if (isFull()) { // Check if queue is full
printf("Queue Overflow\n"); // Print error message
} else {
if (front == -1) { // If queue was empty
front = 0; // Set front to the first position
}
rear++; // Increment rear
queue[rear] = item; // Place the item at rear position
printf("%d enqueued to queue\n", item);
}
}

// Function to remove an element from the queue


int dequeue() {
if (isEmpty()) { // Check if queue is empty
printf("Queue Underflow\n"); // Print error message
return -1; // Return error value
} else {
int item = queue[front]; // Get the front item
front++; // Increment front
if (front > rear) { // If the last item was dequeued
front = rear = -1; // Reset front and rear
}
return item; // Return the item
}
}

// Function to get the front element without removing it


int getFront() {
if (isEmpty()) { // Check if queue is empty
printf("Queue is empty\n"); // Print error message
return -1; // Return error value
} else {
return queue[front]; // Return the front item
}
}
// Sample usage
int main() {
enqueue(10); // Add 10 to queue
enqueue(20); // Add 20 to queue
enqueue(30); // Add 30 to queue
printf("Front element: %d\n", getFront()); // Should print 10
printf("Dequeued: %d\n", dequeue()); // Should print 10
printf("Dequeued: %d\n", dequeue()); // Should print 20
printf("Front element after dequeues: %d\n", getFront()); // Should print 30
return 0;
}

Algorithm Explanation for Queue Operations:

1. Initialization:
Create an array of fixed size (MAX)
Initialize front = -1 and rear = -1 (indicating empty queue)

2. isFull() Operation:
Check if rear == MAX-1
If true, queue is full, return 1

Otherwise, return 0

3. isEmpty() Operation:
Check if front == -1 OR front > rear

If true, queue is empty, return 1


Otherwise, return 0

4. enqueue() Operation:
Check if queue is full using isFull()

If full, print "Queue Overflow"

Otherwise:
If front == -1, set front = 0 (first element)

Increment rear
Place the new item at queue[rear]

5. dequeue() Operation:
Check if queue is empty using isEmpty()
If empty, print "Queue Underflow" and return error value (-1)

Otherwise:
Store the value at queue[front] in a variable
Increment front

If front > rear (last element was dequeued), reset front and rear to -1
Return the stored value

6. getFront() Operation:
Check if queue is empty using isEmpty()

If empty, print "Queue is empty" and return error value (-1)

Otherwise, return the value at queue[front]

Problem with Simple Queue Implementation:

Space Inefficiency: Once the queue is full and elements are dequeued, the front moves forward
leaving unused space at the beginning
Cannot reuse the free space without resetting the queue completely
<a id="circular-queue"></a>

Circular Queue
A circular queue solves the problem of wasted space in a simple queue by making the array circular
(connecting the end to the beginning).
c
#include <stdio.h>
#define MAX 5 // Maximum size of circular queue

// Global variables
int cqueue[MAX]; // Array to store circular queue elements
int front = -1; // Index of front element
int rear = -1; // Index of rear element

// Function to check if circular queue is full


int isFull() {
if ((front == 0 && rear == MAX - 1) || (front == rear + 1)) {
return 1; // Return true (queue is full)
} else {
return 0; // Return false (queue is not full)
}
}

// Function to check if circular queue is empty


int isEmpty() {
if (front == -1) { // If front is -1
return 1; // Return true (queue is empty)
} else {
return 0; // Return false (queue is not empty)
}
}

// Function to add an element to the circular queue


void enqueue(int item) {
if (isFull()) { // Check if queue is full
printf("Circular Queue Overflow\n"); // Print error message
} else {
if (front == -1) { // If queue was empty
front = 0; // Set front to the first position
}
rear = (rear + 1) % MAX; // Increment rear in circular manner
cqueue[rear] = item; // Place the item at rear position
printf("%d enqueued to circular queue\n", item);
}
}

// Function to remove an element from the circular queue


int dequeue() {
if (isEmpty()) { // Check if queue is empty
printf("Circular Queue Underflow\n"); // Print error message
return -1; // Return error value
} else {
int item = cqueue[front]; // Get the front item
if (front == rear) { // If the last item was dequeued
front = rear = -1; // Reset front and rear
} else {
front = (front + 1) % MAX; // Increment front in circular manner
}
return item; // Return the item
}
}

// Function to get the front element without removing it


int getFront() {
if (isEmpty()) { // Check if queue is empty
printf("Circular Queue is empty\n"); // Print error message
return -1; // Return error value
} else {
return cqueue[front]; // Return the front item
}
}

// Sample usage
int main() {
enqueue(10); // Add 10 to queue
enqueue(20); // Add 20 to queue
enqueue(30); // Add 30 to queue
enqueue(40); // Add 40 to queue
printf("Front element: %d\n", getFront()); // Should print 10
printf("Dequeued: %d\n", dequeue()); // Should print 10
printf("Dequeued: %d\n", dequeue()); // Should print 20
// Now we can add more elements even though the array is "full"
enqueue(50); // Add 50 to queue
enqueue(60); // Add 60 to queue
printf("Front element after changes: %d\n", getFront()); // Should print 30
return 0;
}

Algorithm Explanation for Circular Queue Operations:

1. Initialization:
Create an array of fixed size (MAX)
Initialize front = -1 and rear = -1 (indicating empty queue)

2. isFull() Operation:
Check if (front == 0 AND rear == MAX-1) OR (front == rear+1)

If true, circular queue is full, return 1

Otherwise, return 0

3. isEmpty() Operation:
Check if front == -1
If true, circular queue is empty, return 1

Otherwise, return 0

4. enqueue() Operation:
Check if queue is full using isFull()

If full, print "Circular Queue Overflow"


Otherwise:
If front == -1, set front = 0 (first element)

Update rear = (rear + 1) % MAX (circular increment)


Place the new item at cqueue[rear]

5. dequeue() Operation:
Check if queue is empty using isEmpty()
If empty, print "Circular Queue Underflow" and return error value (-1)

Otherwise:
Store the value at cqueue[front] in a variable

If front == rear (last element), reset front and rear to -1


Otherwise, update front = (front + 1) % MAX (circular increment)

Return the stored value

6. getFront() Operation:
Check if queue is empty using isEmpty()

If empty, print "Circular Queue is empty" and return error value (-1)
Otherwise, return the value at cqueue[front]

Visual Representation of Circular Queue:


[0]
[4] [1]

[3] [2]

<a id="priority-queue"></a>

Priority Queue
A priority queue is a queue where elements

You might also like