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

Sorting

The document provides various algorithms for linked list operations and sorting techniques, including insertion at the beginning, end, and specific positions in a linked list. It details sorting algorithms such as Bubble Sort, Selection Sort, Insertion Sort, Quick Sort, and Merge Sort, along with their implementations, advantages, disadvantages, and complexity analyses. Each sorting algorithm is explained with code examples and characteristics, highlighting their efficiency and use cases.

Uploaded by

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

Sorting

The document provides various algorithms for linked list operations and sorting techniques, including insertion at the beginning, end, and specific positions in a linked list. It details sorting algorithms such as Bubble Sort, Selection Sort, Insertion Sort, Quick Sort, and Merge Sort, along with their implementations, advantages, disadvantages, and complexity analyses. Each sorting algorithm is explained with code examples and characteristics, highlighting their efficiency and use cases.

Uploaded by

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

Insert Node at Beginning

void push(Node** head_ref, int new_data)


{

// 1. allocate node
Node* new_node = new Node();
// 2. put in the data
new_node->data = new_data;
// 3. Make next of new node as head
new_node->next = (*head_ref);
// 4. Move the head to point to
// the new node
(*head_ref) = new_node;
}

Insert node at the last


void append(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node
= (struct Node*)malloc(sizeof(struct Node));

struct Node* last = *head_ref; /* used in step 5*/

/* 2. put in the data */


new_node->data = new_data;

/* 3. This new node is going to be the last node, so


make next of it as NULL*/
new_node->next = NULL;

/* 4. If the Linked List is empty, then make the new


* node as head */
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}

/* 5. Else traverse till the last node */


while (last->next != NULL)
last = last->next;

/* 6. Change the next of last node */


last->next = new_node;
return;
}

Insert at any Position


void insertAfter(struct Node* prev_node, int new_data)
{
/*1. check if the given prev_node is NULL */
if (prev_node == NULL)
{
printf("the given previous node cannot be NULL");
return;
}

/* 2. allocate new node */


struct Node* new_node
= (struct Node*)malloc(sizeof(struct Node));

/* 3. put in the data */


new_node->data = new_data;

/* 4. Make next of new node as next of prev_node */


new_node->next = prev_node->next;

/* 5. move the next of prev_node as new_node */


prev_node->next = new_node;
}

Sorting:
A Sorting Algorithm is used to rearrange a given array or list of elements according to a comparison
operator on the elements. The comparison operator is used to decide the new order of elements in the
respective data structure.
Bubble Sort:
Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements
if they are in the wrong order. This algorithm is not suitable for large data sets as its average and
worst-case time complexity is quite high.
Write a program for Bubble Sort.
#include <stdbool.h>
#include <stdio.h>
void swap(int* xp, int* yp)
{
int temp = *xp;
*xp = *yp;
*yp = temp;
}
// An optimized version of Bubble Sort
void bubbleSort(int arr[], int n)
{
int i, j;
bool swapped;
for (i = 0; i < n - 1; i++) {
swapped = false;
for (j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(&arr[j], &arr[j + 1]);
swapped = true;
}
}

// If no two elements were swapped by inner loop,


// then break
if (swapped == false)
break;
}
}

// Function to print an array


void printArray(int arr[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
}
// Driver program to test above functions
int main()
{
int arr[] = { 64, 34, 25, 12, 22, 11, 90 };
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
printf("Sorted array: \n");
printArray(arr, n);
return 0;
}
Advantages of Bubble Sort:
 Bubble sort is easy to understand and implement.
 It does not require any additional memory space.
 It is a stable sorting algorithm, meaning that elements with the same key value maintain their
relative order in the sorted output.
Disadvantages of Bubble Sort:
 Bubble sort has a time complexity of O(N2) which makes it very slow for large data sets.
 Bubble sort is a comparison-based sorting algorithm, which means that it requires a
comparison operator to determine the relative order of elements in the input data set. It can
limit the efficiency of the algorithm in certain cases.
Other Fact About Bubble Sort:
 Bubble sort takes minimum time (Order of n) when elements are already sorted. Hence it is
best to check if the array is already sorted or not beforehand, to avoid O(N2) time complexity.
 Yes, Bubble sort performs the swapping of adjacent pairs without the use of any major data
structure. Hence Bubble sort algorithm is an in-place algorithm.
 Yes, the bubble sort algorithm is stable.
 Due to its simplicity, bubble sort is often used to introduce the concept of a sorting
algorithm. In computer graphics, it is popular for its capability to detect a tiny error (like a
swap of just two elements) in almost-sorted arrays and fix it with just linear complexity (2n).
Selection Sort:
Selection sort is a simple and efficient sorting algorithm that works by repeatedly selecting the
smallest (or largest) element from the unsorted portion of the list and moving it to the sorted portion
of the list.
The algorithm repeatedly selects the smallest (or largest) element from the unsorted portion of the list
and swaps it with the first element of the unsorted part. This process is repeated for the remaining
unsorted portion until the entire list is sorted.
// C program for implementation of selection sort
#include <stdio.h>
void swap(int *xp, int *yp)
{
int temp = *xp;
*xp = *yp;
*yp = temp;
}
void selectionSort(int arr[], int n)
{
int i, j, min_idx;
// One by one move boundary of unsorted subarray
for (i = 0; i < n-1; i++)
{
// Find the minimum element in unsorted array
min_idx = i;
for (j = i+1; j < n; j++)
if (arr[j] < arr[min_idx])
min_idx = j;
// Swap the found minimum element with the first element
if(min_idx != i)
swap(&arr[min_idx], &arr[i]);
}
}
/* Function to print an array */
void printArray(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// Driver program to test above functions
int main()
{
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr)/sizeof(arr[0]);
selectionSort(arr, n);
printf("Sorted array: \n");
printArray(arr, n);
return 0;
}

Complexity Analysis of Selection Sort


 Time Complexity: The time complexity of Selection Sort is O(N2) as there are two nested
loops:
 One loop to select an element of Array one by one = O(N)
 Another loop to compare that element with every other Array element = O(N)
 Therefore overall complexity = O(N) * O(N) = O(N*N) = O(N2)
Auxiliary Space: O(1) as the only extra memory used is for temporary variables while swapping two
values in Array. The selection sort never makes more than O(N) swaps and can be useful when
memory writing is costly.

Advantages of Selection Sort Algorithm


 Simple and easy to understand.
 Works well with small datasets.
Disadvantages of the Selection Sort Algorithm
 Selection sort has a time complexity of O(n^2) in the worst and average case.
 Does not work well on large datasets.
 Does not preserve the relative order of items with equal keys which means it is not stable.
Other fact about Selection Sort
 The default implementation of the Selection Sort Algorithm is not stable. However, it can be
made stable. Please see the stable Selection Sort for details.
 Yes, Selection Sort Algorithm is an in-place algorithm, as it does not require extra space.
Insertion Sort:
Insertion sort is a simple sorting algorithm that works similar to the way you sort playing cards in
your hands. The array is virtually split into a sorted and an unsorted part. Values from the unsorted
part are picked and placed at the correct position in the sorted part.
“To sort an array of size N in ascending order iterate over the array and compare the current element
(key) to its predecessor, if the key element is smaller than its predecessor, compare it to the elements
before. Move the greater elements one position up to make space for the swapped element.”
// C++ program for insertion sort

#include <bits/stdc++.h>
using namespace std;

// Function to sort an array using


// insertion sort
void insertionSort(int arr[], int n)
{
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i];
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 = j - 1;
}
arr[j + 1] = key;
}
}

// A utility function to print an array


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

// Driver code
int main()
{
int arr[] = { 12, 11, 13, 5, 6 };
int N = sizeof(arr) / sizeof(arr[0]);

insertionSort(arr, N);
printArray(arr, N);

return 0;
}
Complexity Analysis of Insertion Sort:
 Time Complexity of Insertion Sort
 The worst-case time complexity of the Insertion sort is O(N^2)
 The average case time complexity of the Insertion sort is O(N^2)
 The time complexity of the best case is O(N).
Space Complexity of Insertion Sort
 The auxiliary space complexity of Insertion Sort is O(1)
Characteristics of Insertion Sort
 This algorithm is one of the simplest algorithms with a simple implementation
 Basically, Insertion sort is efficient for small data values
 Insertion sort is adaptive in nature, i.e. it is appropriate for data sets that are already partially
sorted.
Other Fact about Insertion Sort
 Insertion sort takes the maximum time to sort if elements are sorted in reverse order. And it
takes minimum time (Order of n) when elements are already sorted.
 The Insertion Sort algorithm follows an incremental approach.
 Yes, insertion sort is an in-place sorting algorithm.
 Insertion sort is used when number of elements is small. It can also be useful when the input
array is almost sorted, and only a few elements are misplaced in a complete big array.
Quick Sort Algorithm
QuickSort is a Divide and Conquer algorithm. It picks an element as a pivot and partitions the given
array around the pivot. There are many different versions of quickSort that pick the pivot in different
ways.
 Always pick the first element as a pivot.
 Always pick the last element as a pivot.
 Pick a random element as a pivot.
 Pick the median as the pivot.
Quick Sort by picking the first element as the Pivot.
The key function in quick sort is a partition. The target of partitions is to put the pivot in its correct
position if the array is sorted and the smaller (or equal) to its left and higher elements to its right and
do all this in linear time.
Partition Algorithm:
 We start from the leftmost element and keep track of the index of smaller (or equal) elements
as i.
 While traversing, if we find a smaller (or equal) element, we swap the current element with
arr[i].
 Otherwise, we ignore the current element.
 /* This function takes first element as pivot, places the pivot element at its correct position in
sorted array, and places all smaller (smaller than or equal to pivot) to left of pivot and all
greater elements to right of pivot */
partition (arr[], low, high) {
// first element as pivot
pivot = arr[low]
k = high
for (i = high; i > low; i–) {
if (arr[i] > pivot){
swap arr[i] and arr[k];
k–;
}
}
swap arr[k] and arr[low]
return k-1;
}

/* C++ implementation of QuickSort by taking first element


* as pivot */
#include <bits/stdc++.h>
using namespace std;

/*This function takes first element as pivot, the function


places the pivot element(first element) on its sorted
position and all the element lesser than pivot will placed
left to it, and all the element greater than pivot placed
right to it.*/

int partition(int arr[], int low, int high)


{

// First element as pivot


int pivot = arr[low];
int st = low; // st points to the starting of array
int end = high; // end points to the ending of the array
int k = high;
for (int i = high; i > low; i--) {
if (arr[i] > pivot)
swap(arr[i], arr[k--]);
}
swap(arr[low], arr[k]);
// As we got pivot element index is end
// now pivot element is at its sorted position
// return pivot element index (end)
return k;
}

/* The main function that implements QuickSort


arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(int arr[], int low, int high)
{
// If low is lesser than high
if (low < high) {
// idx is index of pivot element which is at its
// sorted position
int idx = partition(arr, low, high);

// Separately sort elements before


// partition and after partition
quickSort(arr, low, idx - 1);
quickSort(arr, idx + 1, high);
}
}

/* Function to print an array */


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

// Driver Code
int main()
{
int arr[] = { 7, 6, 10, 5, 9, 2, 1, 15, 7 };
int n = sizeof(arr) / sizeof(arr[0]);
quickSort(arr, 0, n - 1);
cout << "Sorted array: \n";
printArray(arr, n);
return 0;
}

Complexity Analysis:
Time Complexity:
 Average Case: O(N * logN), where N is the length of the array.
 Best Case: O(N * logN)
 Worst Case: O(N2)
Auxiliary Space: O(1)
Merge Sort
Merge sort is defined as a sorting algorithm that works by dividing an array into smaller subarrays,
sorting each subarray, and then merging the sorted subarrays back together to form the final sorted
array.
“Merge sort is a recursive algorithm that continuously splits the array in half until it cannot be
further divided i.e., the array has only one element left (an array with one element is always sorted).
Then the sorted subarrays are merged into one sorted array”.
// C program for Merge Sort
#include <stdio.h>
#include <stdlib.h>

// Merges two subarrays of arr[].


// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;

// Create temp arrays


int L[n1], R[n2];

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


for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];

// Merge the temp arrays back into arr[l..r


i = 0;
j = 0;
k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}

// Copy the remaining elements of L[],


// if there are any
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}

// Copy the remaining elements of R[],


// if there are any
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}

// l is for left index and r is right index of the


// sub-array of arr to be sorted
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
int m = l + (r - l) / 2;

// Sort first and second halves


mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);

merge(arr, l, m, r);
}
}

// Function to print an array


void printArray(int A[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}

// Driver code
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int arr_size = sizeof(arr) / sizeof(arr[0]);

printf("Given array is \n");


printArray(arr, arr_size);

mergeSort(arr, 0, arr_size - 1);

printf("\nSorted array is \n");


printArray(arr, arr_size);
return 0;
}
 Time Complexity: O(N log(N)),
 Auxiliary Space: O(N), In merge sort all elements are copied into an auxiliary array. So N
auxiliary space is required for merge sort.
Applications of Merge Sort:
 Sorting large datasets: Merge sort is particularly well-suited for sorting large datasets due to
its guaranteed worst-case time complexity of O(n log n).
 External sorting: Merge sort is commonly used in external sorting, where the data to be sorted
is too large to fit into memory.
 Custom sorting: Merge sort can be adapted to handle different input distributions, such as
partially sorted, nearly sorted, or completely unsorted data.
 Inversion Count Problem
Advantages of Merge Sort:
 Stability: Merge sort is a stable sorting algorithm, which means it maintains the relative order
of equal elements in the input array.
 Guaranteed worst-case performance: Merge sort has a worst-case time complexity of O(N
logN), which means it performs well even on large datasets.
 Parallelizable: Merge sort is a naturally parallelizable algorithm, which means it can be easily
parallelized to take advantage of multiple processors or threads.
Drawbacks of Merge Sort:
 Space complexity: Merge sort requires additional memory to store the merged sub-arrays
during the sorting process.
 Not in-place: Merge sort is not an in-place sorting algorithm, which means it requires
additional memory to store the sorted data. This can be a disadvantage in applications where
memory usage is a concern.
 Not always optimal for small datasets: For small datasets, Merge sort has a higher time
complexity than some other sorting algorithms, such as insertion sort. This can result in
slower performance for very small datasets.

Heap Sort:
Heap sort is a comparison-based sorting technique based on Binary Heap data structure. It is similar to
the selection sort where we first find the minimum element and place the minimum element at the
beginning. Repeat the same process for the remaining elements.

Algorithm of Heap Sort:


First convert the array into heap data structure using heapify, then one by one
delete the root node of the Max-heap and replace it with the last node in the heap
and then heapify the root of the heap. Repeat this process until size of heap is
greater than 1.
 Build a heap from the given input array.
 Repeat the following steps until the heap contains only one element:
 Swap the root element of the heap (which is the largest element)
with the last element of the heap.
 Remove the last element of the heap (which is now in the correct
position).
 Heapify the remaining elements of the heap.
 The sorted array is obtained by reversing the order of the elements in the
input array.
 // Heap Sort in C
//C Program of Heap Sort
#include <stdio.h>
// Function to swap the position of two elements

void swap(int* a, int* b)


{

int temp = *a;


*a = *b;
*b = temp;
}

// To heapify a subtree rooted with node i


// which is an index in arr[].
// n is size of heap
void heapify(int arr[], int N, int i)
{
// Find largest among root,
// left child and right child

// Initialize largest as root


int largest = i;

// left = 2*i + 1
int left = 2 * i + 1;

// right = 2*i + 2
int right = 2 * i + 2;

// If left child is larger than root


if (left < N && arr[left] > arr[largest])

largest = left;

// If right child is larger than largest


// so far
if (right < N && arr[right] > arr[largest])

largest = right;

// Swap and continue heapifying


// if root is not largest
// If largest is not root
if (largest != i) {

swap(&arr[i], &arr[largest]);

// Recursively heapify the affected


// sub-tree
heapify(arr, N, largest);
}
}
// Main function to do heap sort
void heapSort(int arr[], int N)
{

// Build max heap


for (int i = N / 2 - 1; i >= 0; i--)

heapify(arr, N, i);

// Heap sort
for (int i = N - 1; i >= 0; i--) {

swap(&arr[0], &arr[i]);

// Heapify root element


// to get highest element at
// root again
heapify(arr, i, 0);
}
}

// A utility function to print array of size n


void printArray(int arr[], int N)
{
for (int i = 0; i < N; i++)
printf("%d ", arr[i]);
printf("\n");
}

// Driver's code
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int N = sizeof(arr) / sizeof(arr[0]);

// Function call
heapSort(arr, N);
printf("Sorted array is\n");
printArray(arr, N);
}

You might also like