0% found this document useful (0 votes)
6 views17 pages

Data Structure

The document provides an overview of various sorting algorithms including Quick Sort, Merge Sort, and Insertion Sort, detailing their mechanisms and implementations in C++. It also introduces the concept of Greedy Algorithms, explaining their approach, advantages, and limitations, alongside examples like Coin Change and Activity Selection. Additionally, it briefly discusses the Knapsack Problem and its types, emphasizing the optimization aspect in algorithm design.

Uploaded by

fatima.yaseen432
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views17 pages

Data Structure

The document provides an overview of various sorting algorithms including Quick Sort, Merge Sort, and Insertion Sort, detailing their mechanisms and implementations in C++. It also introduces the concept of Greedy Algorithms, explaining their approach, advantages, and limitations, alongside examples like Coin Change and Activity Selection. Additionally, it briefly discusses the Knapsack Problem and its types, emphasizing the optimization aspect in algorithm design.

Uploaded by

fatima.yaseen432
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Algorithms

What is Quick Sort?

Quick Sort is a Divide and Conquer algorithm.


It:

1. Picks a pivot element.


2. Puts all smaller elements to the left of the pivot, and larger ones to the right.
3. Then it recursively sorts the left and right parts.

Now let’s understand the code piece by piece:

1. Swap Function
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}

This is a simple helper function to swap two numbers.


If a = 5 and b = 10, after swap(a, b), a becomes 10 and b becomes 5.

2. Partition Function
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // last element is pivot
int i = low - 1;
for (int j = low; j < high; j++) {

if (arr[j] < pivot) {


i++;
swap(arr[i], arr[j]); // put smaller
elements to the left
}
}

swap(arr[i + 1], arr[high]); // put pivot in correct


place
return i + 1; // return pivot position
}

Explanation:

• pivot is the last element (we compare everything with this).


• i is used to track the "boundary" of smaller elements.
• Inside the loop:
If the current element arr[j] is smaller than the pivot:
o Increase i and swap arr[i] with arr[j].
• After the loop, we place the pivot in its correct sorted place.

3. QuickSort Function
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high); // get pivot
index

quickSort(arr, low, pi - 1); // sort left part


quickSort(arr, pi + 1, high); // sort right part
}
}

Explanation:
• We use the partition function to get the pivot index.
• Then we recursively sort:

o Left side of the pivot: low to pi-1


o Right side of the pivot: pi+1 to high

4. Main Function
int main() {
int arr[] = { 10, 7, 8, 9, 1, 5 };
int n = sizeof(arr) / sizeof(arr[0]);

cout << "Original array: ";


printArray(arr, n);

quickSort(arr, 0, n - 1);

cout << "Sorted array: ";


printArray(arr, n);

return 0;
}

• An array {10, 7, 8, 9, 1, 5} is given.


• We call quickSort to sort it.
• Then print the sorted array.

C++ Program for Merge Sort


#include <iostream>
using namespace std;
// Function to merge two subarrays
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1; // Size of first half
int n2 = right - mid; // Size of second half

int L[n1], R[n2]; // Temporary arrays

// Copy data to temporary arrays L[] and R[]


for (int i = 0; i < n1; i++)
L[i] = arr[left + i];

for (int j = 0; j < n2; j++)


R[j] = arr[mid + 1 + j];

// Merge the temp arrays back into arr[left..right]


int i = 0, j = 0, k = left;

while (i < n1 && j < n2) {


if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}

// Copy remaining elements of L[] if any


while (i < n1) {
arr[k] = L[i];
i++;
k++;
}

// Copy remaining elements of R[] if any


while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}

// Recursive merge sort function


void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;

// Sort the first and second halves


mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);

// Merge the sorted halves


merge(arr, left, mid, right);
}
}

// Function to print the array


void printArray(int arr[], int size) {
for (int i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}

// Main function
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr) / sizeof(arr[0]);

cout << "Original array: ";


printArray(arr, n);

mergeSort(arr, 0, n - 1);

cout << "Sorted array: ";


printArray(arr, n);

return 0;
}

Detailed Explanation

1. Merge Sort Concept


Merge Sort is a Divide and Conquer algorithm.

It:

1. Divides the array into two halves.


2. Recursively sorts both halves.
3. Merges the two sorted halves into one.

2. merge() Function
void merge(int arr[], int left, int mid, int right)

This function merges two sorted parts:

• From left to mid


• From mid+1 to right

int n1 = mid - left + 1;


int n2 = right - mid;

Calculate the sizes of two subarrays.

int L[n1], R[n2];

Create two temporary arrays:

• L[] will hold left half


• R[] will hold right half
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];

Copy data into the left temp array L.

for (int j = 0; j < n2; j++)


R[j] = arr[mid + 1 + j];

Copy data into the right temp array R.

int i = 0, j = 0, k = left;

Initialize pointers:

• i for left array L


• j for right array R
• k for actual array arr

while (i < n1 && j < n2)

Compare elements of both arrays, insert the smaller one into original array.
if (L[i] <= R[j])
arr[k] = L[i++];
else
arr[k] = R[j++];
k++;

while (i < n1)


arr[k++] = L[i++];

Copy remaining elements from L, if any.

while (j < n2)


arr[k++] = R[j++];
Copy remaining elements from R, if any.

3. mergeSort() Function
void mergeSort(int arr[], int left, int right)

This function recursively divides and sorts the array.


if (left < right) {
int mid = left + (right - left) / 2;

If array has more than one element, split it into two parts.
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);

Recursively sort both halves.


merge(arr, left, mid, right);

Then merge the two sorted halves.

4. main() Function
int arr[] = {12, 11, 13, 5, 6, 7};

We create an array to be sorted.


int n = sizeof(arr) / sizeof(arr[0]);

Find the number of elements in the array.


printArray(arr, n);
mergeSort(arr, 0, n - 1);
printArray(arr, n);

Print the original array, sort it using mergeSort, then print the sorted array.
Insertion Sort :
Idea:
Insertion Sort builds the final sorted array one element at a time by comparing and inserting the current
element into its correct position among the already sorted elements.

Steps:

1. Start from the second element (index 1) assuming the first element is already "sorted".
2. Compare it with elements on its left.
3. Shift all greater elements one position to the right.
4. Insert the current element into the correct position.
5. Repeat until the entire array is sorted.

Example:

Sort this array:


[5, 2, 4, 6, 1, 3]

Pass 1: (key = 2)
Compare with 5 → shift 5 → Insert 2
→ [2, 5, 4, 6, 1, 3]

Pass 2: (key = 4)
Compare with 5 → shift 5 → Insert 4
→ [2, 4, 5, 6, 1, 3]

Pass 3: (key = 6)
Already in correct place
→ [2, 4, 5, 6, 1, 3]

Pass 4: (key = 1)
Compare with 6, 5, 4, 2 → shift all
→ Insert 1
→ [1, 2, 4, 5, 6, 3]

Pass 5: (key = 3)
Compare with 6, 5, 4 → shift all → insert 3
→ [1, 2, 3, 4, 5, 6]
Time Complexity:

• Best Case (Already Sorted): O(n)


• Worst & Average Case: O(n²)

Here’s the C++ code for Insertion Sort with comments to help you understand each step:

#include <iostream>
using namespace std;

void insertionSort(int arr[], int n) {


for (int i = 1; i < n; i++) {
int key = arr[i]; // current element to be inserted
int j = i - 1;

// Move elements of arr[0..i-1] that are greater than key


// to one position ahead of their current position

while (j >= 0 && arr[j] > key) {


arr[j + 1] = arr[j];
j--;
}

arr[j + 1] = key; // Insert the key in the correct position


}
}

// Function to print array


void printArray(int arr[], int n) {
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
}

// Main function
int main() {
int arr[] = {5, 2, 4, 6, 1, 3};
int n = sizeof(arr) / sizeof(arr[0]);

cout << "Original array: ";


printArray(arr, n);

insertionSort(arr, n);

cout << "Sorted array: ";


printArray(arr, n);

return 0;
}

Output:
Original array: 5 2 4 6 1 3
Sorted array: 1 2 3 4 5 6
What is a Greedy Algorithm?
Imagine you're solving a problem and, at every step, you simply choose what looks
best at that moment, without thinking too much about the future. That’s the greedy
approach.

It’s like eating your favorite food from a plate — you pick the tastiest piece first
every time, hoping that by doing that, the entire meal will be enjoyable.

A greedy algorithm works the same way:


It makes the best immediate choice again and again, and hopes that these choices
will give the overall best solution.

How It Works — Step by Step

1. First, you understand what your problem is.


2. Then, you figure out how to measure what’s the “best” choice at each step.
3. Every time you make a move, you choose the best-looking option right now.
4. You don’t go back to fix past choices — just keep moving forward.
5. You repeat this until the problem is solved.

So basically: Best now → Move on → Repeat.

Let’s Take a Simple Example — Coin Change

Say you want to make 37 cents, and you have coins of 25, 10, 5, and 1.

Using a greedy approach:

• First, pick 25 → 37 - 25 = 12 left


• Then, pick 10 → 12 - 10 = 2 left
• Then, two 1s → Done!
Total coins used = 4.
You always picked the biggest coin that fits — that’s greedy thinking.

It works here because this coin system allows the greedy method to give the best
solution.

Another Real Example — Activity Selection

Suppose you have several activities with start and end times, and you want to attend
as many as possible without time clashes.

Let’s say:

• Activity 1: 1:00 to 2:00


• Activity 2: 1:30 to 3:00
• Activity 3: 2:30 to 4:00
• Activity 4: 4:00 to 5:00

The greedy idea here is to pick the activity that ends earliest so you can have more
free time left for the next ones.

So:

• Pick Activity 1
• Skip Activity 2 (overlaps)
• Pick Activity 3
• Pick Activity 4

So you do 3 activities, which is the best possible. Greedy works perfectly here.

But Wait… Does Greedy Always Work?

Nope! That’s the catch.

Greedy only works for certain types of problems — where:

1. Choosing the best step now leads to the best overall answer. (Greedy Choice
Property)
2. The smaller parts of the problem help build the full answer. (Optimal
Substructure)

If these two properties exist, greedy will work great.


If not, greedy might give the wrong answer.

When Greedy Fails: Coin Change Example

Suppose your coins are: 1, 3, and 4 cents, and you want to make 6 cents.

Greedy might choose:

• 4 → then two 1s → total 3 coins

But the better solution is:

• 3 + 3 → only 2 coins

So greedy fails here — because the best short-term choice (4) doesn’t help us get
the best total.

Pros of Greedy Algorithms

• Very simple to write and understand


• Fast, because you don’t check every possibility
• Works perfectly for many real-world problems

Cons of Greedy Algorithms

• Doesn’t always give the best solution


• You can’t go back and fix a bad choice
• It works only for problems that fit the greedy pattern
Where Greedy Works Really Well

• Coin change (for certain coin systems)


• Activity selection
• Huffman coding (used in file compression)
• Kruskal's and Prim’s algorithms (for building networks)
• Dijkstra's algorithm (finding shortest paths)

Quick Real-Life Analogy

Imagine you're shopping with limited money.


A greedy shopper buys the cheapest item every time to get the most things —
without thinking about whether they really need it or whether better deals exist
ahead.
Sometimes it works, sometimes not — but it’s quick!

In a Nutshell:

Greedy algorithms are like thinking:


“What’s the best I can do right now?”
If that’s enough to get you the best total result, greedy works like a charm!

The Knapsack Problem is a classic example of optimization in algorithms. It's


commonly solved using either Greedy, Dynamic Programming, or Backtracking,
depending on the type of problem. Let’s explore it with examples and simple
explanations.

What is the Knapsack Problem?


Imagine you have:

• A bag (knapsack) that can carry only a certain weight.


• A list of items, each with:
o A weight
o A value (profit)

Your goal is to select items to put into the bag so that:

• You maximize the total value


• You don’t exceed the weight limit

Types of Knapsack Problems

1. 0/1 Knapsack: You either take the whole item or leave it (no splitting).
2. Fractional Knapsack: You can take a part of an item (used with greedy).

Example 1: 0/1 Knapsack (Use Dynamic Programming)

You have a bag that can carry weight = 50

Items:

Item Weight Value

A 10 60

B 20 100

C 30 120

You can’t break items. Which items should you pick?

Solution:

Try different combinations:

• A + B = 10+20 = 30 weight → value = 60+100 = 160


• B + C = 20+30 = 50 weight → value = 100+120 = 220
• A + C = 10+30 = 40 weight → value = 60+120 = 180
Best value: 220 (by picking items B and C)

Example 2: Fractional Knapsack (Use Greedy Algorithm)

Same items, but now you can take fractions.

Knapsack weight = 50

Items:

Item Weight Value Value/Weight

A 10 60 6.0

B 20 100 5.0

C 30 120 4.0

Greedy Approach:

• Sort items by value/weight (descending)


• Pick from highest to lowest:

Steps:

1. Pick A (full) → weight = 10 → value = 60


2. Pick B (full) → weight = 20 → value = 100
3. Pick 2/3 of C (20/30 weight) → value = 2/3 * 120 = 80

Total weight = 10 + 20 + 20 = 50
Total value = 60 + 100 + 80 = 240

Best value: 240


Summary:
Type Can Split Solution Type Example Strategy
Items?

0/1 Knapsack No Dynamic Try all valid


Programming combinations

Fractional Yes Greedy Algorithm Pick by value/weight


Knapsack ratio

You might also like