Midterm Exam Study Guide
Topics: Linked List and its Types, Stack, Queue
1. Linked List and its Types
What is a Linked List?
A linked list is a linear data structure where each element (called a node) is connected to the
next using pointers. Unlike arrays, linked lists do not store elements in contiguous memory,
making them dynamic and efficient for certain tasks.
Each node in a linked list contains:
1. Data: The value stored in the node.
2. Pointer (Next): A reference (or pointer) to the next node in the sequence.
Advantages of Linked Lists
Dynamic Size: Can grow or shrink as needed.
Efficient Insertions/Deletions: Inserting or deleting a node does not require shifting elements,
unlike arrays.
Types of Linked Lists
1. Singly Linked List
2. Doubly Linked List
3. Circular Linked List
1.1 Singly Linked List
In a singly linked list, each node points to the next node in the sequence. The last node points to
NULL.
Structure of a Singly Linked List Node (C++ Example):
struct Node {
int data; // Value of the node
Node* next; // Pointer to the next node
};
Operations on Singly Linked List
Insertion: Add a new node to the list.
Deletion: Remove a node from the list.
Traversal: Visit each node and print its data.
Code Example:
#include <iostream>
using namespace std;
// Define a node
struct Node {
int data;
Node* next;
};
// Function to add a node to the end
void append(Node*& head, int newData) {
Node* newNode = new Node();
newNode->data = newData;
newNode->next = NULL;
if (head == NULL) { // If list is empty
head = newNode;
return;
}
Node* temp = head;
while (temp->next != NULL) { // Traverse to the last node
temp = temp->next;
}
temp->next = newNode; // Add new node at the end
}
// Function to print the linked list
void printList(Node* head) {
while (head != NULL) {
cout << head->data << " -> ";
head = head->next;
}
cout << "NULL" << endl;
}
int main() {
Node* head = NULL;
append(head, 10);
append(head, 20);
append(head, 30);
printList(head); // Output: 10 -> 20 -> 30 -> NULL
return 0;
}
1.2 Doubly Linked List
In a doubly linked list, each node contains pointers to both the previous and next nodes. This
allows traversal in both directions.
Structure of a Doubly Linked List Node:
struct Node {
int data;
Node* prev; // Pointer to the previous node
Node* next; // Pointer to the next node
};
Code Example:
#include <iostream>
using namespace std;
// Define a node
struct Node {
int data;
Node* prev;
Node* next;
};
// Function to add a node to the end
void append(Node*& head, int newData) {
Node* newNode = new Node();
newNode->data = newData;
newNode->next = NULL;
if (head == NULL) { // If list is empty
newNode->prev = NULL;
head = newNode;
return;
}
Node* temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
newNode->prev = temp;
}
// Function to print the linked list
void printList(Node* head) {
while (head != NULL) {
cout << head->data << " <-> ";
head = head->next;
}
cout << "NULL" << endl;
}
int main() {
Node* head = NULL;
append(head, 10);
append(head, 20);
append(head, 30);
printList(head); // Output: 10 <-> 20 <-> 30 <-> NULL
return 0;
}
1.3 Circular Linked List
In a circular linked list, the last node points back to the first node, forming a loop.
Structure of Circular Linked List:
struct Node {
int data;
Node* next; // Pointer to the next node (or the head)
};
Code Example:
#include <iostream>
using namespace std;
// Define a node
struct Node {
int data;
Node* next;
};
// Function to add a node
void append(Node*& head, int newData) {
Node* newNode = new Node();
newNode->data = newData;
if (head == NULL) {
head = newNode;
newNode->next = head; // Point to itself
return;
}
Node* temp = head;
while (temp->next != head) {
temp = temp->next;
}
temp->next = newNode;
newNode->next = head;
}
// Function to print the circular linked list
void printList(Node* head) {
if (head == NULL) return;
Node* temp = head;
do {
cout << temp->data << " -> ";
temp = temp->next;
} while (temp != head);
cout << "HEAD" << endl;
}
int main() {
Node* head = NULL;
append(head, 10);
append(head, 20);
append(head, 30);
printList(head); // Output: 10 -> 20 -> 30 -> HEAD
return 0;
}
Summary of Linked Lists
Type Key Feature
Singly Linked List Nodes connected in one direction.
Doubly Linked List Nodes have pointers to previous and next.
Circular Linked List Last node points back to the head.
2. Stack
What is a Stack?
A stack is a linear data structure that follows the LIFO (Last In, First Out) principle. The last
element added is the first one removed.
Stack Operations
1. Push: Add an element to the stack.
2. Pop: Remove the top element.
3. Peek: Retrieve the top element without removing it.
4. isEmpty: Check if the stack is empty.
Code Example (Using STL in C++):
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<int> myStack;
// Push elements
myStack.push(10);
myStack.push(20);
myStack.push(30);
// Access the top element
cout << "Top: " << myStack.top() << endl; // Output: 30
// Pop an element
myStack.pop();
// Check if stack is empty
if (!myStack.empty()) {
cout << "Stack is not empty!" << endl;
} else {
cout << "Stack is empty!" << endl;
}
return 0;
}
3. Queue
What is a Queue?
A queue is a linear data structure that follows the FIFO (First In, First Out) principle. The first
element added is the first one removed.
Queue Operations
1. Enqueue: Add an element to the rear.
2. Dequeue: Remove an element from the front.
3. Front: Retrieve the front element without removing it.
4. isEmpty: Check if the queue is empty.
Code Example (Using STL in C++):
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> myQueue;
// Enqueue elements
myQueue.push(10);
myQueue.push(20);
myQueue.push(30);
// Access the front element
cout << "Front: " << myQueue.front() << endl; // Output: 10
// Dequeue an element
myQueue.pop();
// Check if queue is empty
if (!myQueue.empty()) {
cout << "Queue is not empty!" << endl;
} else {
cout << "Queue is empty!" << endl;
}
return 0;
}
Summary Table
Data Key Features Operations Use Cases
Structure
Linked List Nodes linked Insert, Delete, Dynamic memory,
dynamically Traverse flexibility
Stack LIFO structure Push, Pop, Peek Backtracking, Reversal
Queue FIFO structure Enqueue, Dequeue Scheduling, Buffering
OVERVIEW:
Here’s a list of important topics for your study guide along with a brief overview of each. These
topics are essential for understanding data structures and basic programming concepts in C++.
1. Standard Template Library (STL)
Overview: STL is a collection of pre-defined classes and functions in C++ that help manage
common data structures and algorithms efficiently.
Key Components
:
Containers: Objects that store data (e.g., vector, list, queue, stack, map, set).
Iterators: Used to traverse elements in a container.
Algorithms: Predefined functions for operations like sorting, searching, etc.
Functors: Function objects used in conjunction with STL algorithms.
2. Vector
Overview: A dynamic array that can grow or shrink as needed.
Key Features
:
Contiguous memory allocation (like arrays).
Supports random access using an index.
Functions like push_back(), pop_back(), size(), resize() for dynamic management.
Example: #include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> v = {10, 20, 30};
v.push_back(40); // Add an element
v.pop_back(); // Remove last element
cout << "Size: " << v.size() << endl; // Output: Size: 3
}
3. Struct
Overview: A user-defined data type in C++ that groups related variables (of different types)
together.
Key Features
:
Allows logical grouping of variables.
Accessed using the dot (.) operator.
Example: #include <iostream>
using namespace std;
struct Student {
string name;
int rollNo;
float marks;
};
int main() {
Student s1 = {"John", 101, 85.5};
cout << "Name: " << s1.name << ", Marks: " << s1.marks << endl;
}
4. Arrays
Overview: A fixed-size data structure that stores elements of the same data type in
contiguous memory.
Key Features
:
Static in size (size must be known at compile time).
Indexed-based access.
Example: int arr[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
5. Linked List
Overview: A linear data structure where elements (nodes) are connected using pointers.
Types
:
Singly Linked List: One pointer to the next node.
Doubly Linked List: Two pointers (to the previous and next nodes).
Circular Linked List: Last node points back to the first node.
Uses: Dynamic memory allocation, implementing stacks and queues.
6. Stack
Overview: A LIFO (Last In, First Out) data structure.
Operations
:
push: Add an element.
pop: Remove the top element.
top: Retrieve the top element without removing it.
Example: #include <stack>
stack<int> s;
s.push(10); s.push(20);
cout << s.top(); // Output: 20
7. Queue
Overview: A FIFO (First In, First Out) data structure.
Operations
:
enqueue: Add an element.
dequeue: Remove the front element.
front: Access the first element.
Example: #include <queue>
queue<int> q;
q.push(10); q.push(20);
q.pop();
cout << q.front(); // Output: 20
8. Recursion
Overview: A programming technique where a function calls itself.
Key Features
:
Requires a base case to terminate.
Useful for solving problems like factorial, Fibonacci, etc.
Example: int factorial(int n) {
if (n == 0) return 1;
return n * factorial(n - 1);
}
9. Binary Search
Overview: A divide-and-conquer algorithm for searching in a sorted array.
Steps
:
Divide the array into two halves.
Check the middle element.
Narrow down the search to the left or right half based on the value.
Example: int binarySearch(int arr[], int size, int key) {
int low = 0, high = size - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (arr[mid] == key) return mid;
else if (arr[mid] < key) low = mid + 1;
else high = mid - 1;
}
return -1; // Not found
}
10. Sorting Algorithms
Overview: Algorithms used to arrange elements in ascending or descending order.
Common Types
:
Bubble Sort: Compare adjacent elements and swap.
Selection Sort: Select the minimum element and place it in the correct position.
Insertion Sort: Insert each element into its correct position in a sorted portion.
Quick Sort: Divide-and-conquer algorithm using a pivot element.
Example (Bubble Sort): void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1])
swap(arr[j], arr[j + 1]);
}
}
}
11. Pointers
Overview: Variables that store memory addresses.
Key Features
:
Access and manipulate memory directly.
Used for dynamic memory allocation and linked lists.
Example: int a = 10;
int* p = &a;
cout << *p; // Output: 10
12. Dynamic Memory Allocation
Overview: Allocating memory during runtime using pointers.
Key Functions
:
new: Allocates memory.
delete: Frees memory.
Example: int* ptr = new int(5);
cout << *ptr; // Output: 5
delete ptr; // Free memory
13. Maps and Sets
Maps
:
A key-value pair container.
Keys are unique, values can be accessed using keys.
Sets
:
A container with unique elements.
Useful for eliminating duplicates.
Example (Map): #include <map>
map<int, string> m;
m[1] = "Alice";
m[2] = "Bob";
cout << m[1]; // Output: Alice
14. Object-Oriented Programming (OOP) Concepts
Key Concepts
:
Class: Blueprint for creating objects.
Object: Instance of a class.
Encapsulation: Wrapping data and methods into a single unit.
Inheritance: Reusing code by deriving new classes from existing ones.
Polymorphism: Ability to use methods in different ways (e.g., function overloading).
Example (Class and Object): class Car {
public:
string brand;
void start() {
cout << "Car started" << endl;
}
};
int main() {
Car c1;
c1.brand = "Toyota";
c1.start();
}