dsa unit 1 (ai)
dsa unit 1 (ai)
Each data structure has its advantages and is chosen based on the problem
requirements.
1. Time Complexity: Measures how the execution time of an algorithm changes
with input size.
2. Space Complexity: Measures the additional memory required by an algorithm.
For practical purposes, algorithms with lower time complexities are preferred as they
scale efficiently with large inputs.
Common ADTs:
ADTs define the behavior of a data structure, while the actual implementation can vary.
Arrays
An array is a linear data structure that stores elements of the same data type in
contiguous memory locations.
Types of Arrays:
1.
2.
3. Dynamic Arrays: Implemented using pointers and memory allocation
(malloc()/new).
#include <iostream>
int main() {
cout << "First Element: " << *ptr << endl; // Output: 10
ptr++;
cout << "Second Element: " << *ptr << endl; // Output: 20
return 0;
Dynamic memory allocation is useful when the array size is unknown at compile time.
This prevents memory wastage when handling unknown or varying input sizes.
Multidimensional Arrays
A multidimensional array is an array of arrays, meaning it can store data in multiple
dimensions (2D, 3D, etc.).
{4, 5, 6},
{7, 8, 9} };
Each element in a 2D array is accessed using row index and column index.
Declaration
Since arrays in C++ are stored in row-major order, a 2D array can be represented
using pointers.
String Processing
A string is a sequence of characters stored in contiguous memory. In C++, strings can
be handled using:
A string in C can be stored as a character array, ending with a null character (\0).
char str[] = "Hello"; // Stored as {'H', 'e', 'l', 'l', 'o', '\0'}
char name[20];
cin >> name; // Reads a single word
cin.getline(name, 20);
#include <iostream>
#include <cstring>
int main() {
return 0;
}
Function Description
The string class in C++ provides an easier way to work with strings.
#include <iostream>
#include <string>
int main() {
return 0;
Function Description
Types of Lists:
List Manipulations
List manipulations involve performing various operations on lists, such as insertion,
deletion, searching, and updating.
1. Insertion in a List
newNode->data = newData;
newNode->next = *head;
*head = newNode;
}
(b) Inserting at the end
newNode->data = newData;
newNode->next = NULL;
if (*head == NULL) {
*head = newNode;
return;
temp = temp->next;
temp->next = newNode;
2. Deletion in a List
*head = temp->next;
delete temp;
return;
prev = temp;
temp = temp->next;
prev->next = temp->next;
delete temp;
3. Searching in a List
if (current->data == key)
return true;
current = current->next;
return false;
4. Reversing a List
void reverseList(Node** head) {
next = current->next;
current->next = prev;
prev = current;
current = next;
*head = prev;
bool swapped;
Node* ptr1;
do {
swapped = false;
ptr1 = head;
swap(ptr1->data, ptr1->next->data);
swapped = true;
}
ptr1 = ptr1->next;
lptr = ptr1;
} while (swapped);
struct Node {
int data;
Node* next;
};
newNode->data = newData;
newNode->next = *head;
*head = newNode;
temp = temp->next;
A doubly linked list is similar to a singly linked list but has an additional pointer to the
previous node.
Each node consists of:
struct Node {
int data;
Node* next;
Node* prev;
};
newNode->data = newData;
newNode->next = *head;
newNode->prev = NULL;
if (*head != NULL)
(*head)->prev = newNode;
*head = newNode;
temp = temp->next;
● The last node's next pointer points back to the first node (for singly circular list).
● In a doubly circular list, the prev pointer of the first node points to the last node.
struct Node {
int data;
Node* next;
};
newNode->data = newData;
newNode->next = *head;
if (*head == NULL) {
*head = newNode;
newNode->next = *head;
} else {
temp = temp->next;
temp->next = newNode;
newNode->next = *head;
do {
temp = temp->next;
The Stack ADT defines a collection of elements with the following operations:
Stack Manipulation
1. Implementation of Stack
struct Stack {
int top;
int arr[MAX];
};
s->top = -1;
if (s->top == MAX - 1) {
return;
s->arr[++s->top] = value;
int pop(Stack* s) {
if (s->top == -1) {
return -1;
return s->arr[s->top--];
if (s->top == -1) {
return -1;
return s->arr[s->top];
bool isEmpty(Stack* s) {
A stack using a linked list allows dynamic memory allocation and avoids fixed-size
limitations.
struct Node {
int data;
Node* next;
};
newNode->data = value;
newNode->next = *top;
*top = newNode;
if (*top == NULL) {
return -1;
*top = (*top)->next;
delete temp;
return popped;
return -1;
return top->data;
4. Applications of Stacks
1. Infix Notation
Definition: The operator is placed between the operands.
Example:
A+B
(A + B) * C
●
● This is the standard way humans write expressions. However, computers find it
difficult to process because it requires operator precedence and parentheses.
1. Parentheses ()
2. Exponents ^
3. Multiplication *, Division /
4. Addition +, Subtraction -
Example Evaluation:
Expression: 3 + 5 * 2
Example:
+ A B → (A + B)
* + A B C → (A + B) * C
●
● No need for parentheses because the order is clear.
(A + B) * C
Convert:
*+ABC
2.
Example:
A B + → (A + B)
A B + C * → (A + B) * C
●
● No need for parentheses, and it is easier for computers to evaluate using
stacks.
(A + B) * C
Convert:
AB+C*
2.
● B * C is computed first.
● A + (result) follows.
● Prefix order: + A * B C
2. Convert Infix to Postfix (A B C * +)
● B * C is computed first.
● A + (result) follows.
● Postfix order: A B C * +
#include <iostream>
#include <stack>
stack<int> s;
if (isdigit(ch))
else {
switch (ch) {
return s.top();
int main() {
return 0;
Parentheses Yes No No
Required?
Recursion
Recursion is a programming technique where a function calls itself to solve a problem.
It is useful for problems that can be broken down into smaller, similar subproblems.
void recursiveFunction() {
if (base_condition)
return;
int factorial(int n) {
5 * factorial(4)
4 * factorial(3)
3 * factorial(2)
2 * factorial(1)
3. Types of Recursion
int fibonacci(int n) {
if (n <= 1) return n;
Queue Manipulation
1. Queue Implementation Using Arrays
Structure of Queue
struct Queue {
int arr[MAX];
};
void initQueue(Queue* q) {
}
(b) Enqueue Operation
if (q->rear == MAX - 1) {
return;
q->arr[++q->rear] = value;
int dequeue(Queue* q) {
return -1;
return q->arr[q->front++];
int front(Queue* q) {
return q->arr[q->front];
}
struct Node {
int data;
Node* next;
};
newNode->data = value;
newNode->next = NULL;
if (*rear == NULL) {
return;
(*rear)->next = newNode;
*rear = newNode;
}
(b) Dequeue Operation (Delete from Front)
if (*front == NULL) {
return -1;
*front = (*front)->next;
delete temp;
return removedData;
Types of Queues
1. Simple Queue – Standard FIFO queue.
2. Circular Queue – Rear wraps around when it reaches the end of the array.
3. Priority Queue – Elements are dequeued based on priority.
4. Deque (Double-Ended Queue) – Insertion and deletion can occur from both
ends.