# Insertion Sort

Insertion sort is a comparison-based sorting algorithm that builds the final sorted array one element at a time. It works by dividing the input array into two regions: a sorted region and an unsorted region. Initially, the sorted region consists of only the first element, and the rest of the array is considered unsorted.

The algorithm iterates through the unsorted region, one element at a time, and compares each element with the elements in the sorted region. It finds the correct position for the current element in the sorted region by shifting the elements greater than it to the right. This shifting creates a space for the current element to be inserted.

To perform the insertion, the algorithm starts from the rightmost element of the sorted region and compares it with the current element. If the element from the sorted region is greater, it is shifted one position to the right. This process continues until the appropriate position for the current element is found.

Once the correct position is determined, the algorithm inserts the current element into the sorted region. This insertion step is repeated for all the elements in the unsorted region, gradually expanding the sorted region until the entire array is sorted.

Insertion sort is an in-place algorithm, meaning it does not require additional memory to perform the sorting. It is also considered a stable sorting algorithm, as it preserves the relative order of elements with equal values.

The time complexity of insertion sort is O(n^2) in the worst-case scenario, where n is the number of elements in the input array. However, in practice, it can have better performance for small or partially sorted arrays. In the best-case scenario, when the input array is already sorted, the time complexity reduces to O(n). The average-case time complexity is also O(n^2), making it less efficient compared to more advanced sorting algorithms like quicksort or mergesort.

Despite its relatively slower performance for large arrays, insertion sort has some advantages. It is easy to understand and implement, making it a suitable choice for small datasets or situations where simplicity is preferred over efficiency. Additionally, it performs well on partially sorted or nearly sorted arrays, requiring fewer comparisons and swaps compared to other algorithms.

In conclusion, insertion sort is a simple and intuitive sorting algorithm that builds the final sorted array by repeatedly inserting elements into their correct positions within the already sorted region. While it may not be the most efficient choice for large datasets, it has its merits and can be a useful tool in certain scenarios.

## History

The insertion sort algorithm has a long history and can be traced back to the early days of computer science. It was first mentioned by the computer scientist and mathematician John von Neumann in 1945, although the algorithm was likely known before that time.

The basic concept of insertion sort can be found in card games like playing cards or bridge. Players often sort their cards by continuously inserting a new card into its correct position in the already sorted hand. This manual sorting technique inspired the development of the insertion sort algorithm.

The algorithm gained prominence with the advent of computers and the need for efficient sorting methods. In the early days of computing, memory was limited, and complex sorting algorithms were not feasible. Insertion sort, with its simplicity and ability to sort small arrays efficiently, became a popular choice.

One of the earliest references to the insertion sort algorithm in the context of computer programming can be found in the book "The Preparation of Programs for an Electronic Digital Computer" by Maurice Wilkes in 1951. Wilkes described the algorithm as a technique to sort a list of numbers in a computer program.

Over the years, insertion sort has been analyzed and studied extensively. Its time complexity and performance characteristics have been well-understood. Researchers have compared insertion sort with other sorting algorithms and identified its strengths and weaknesses.

While insertion sort may not be the most efficient algorithm for large datasets, it has found its applications in various scenarios. It is particularly useful when dealing with small or partially sorted arrays, where its simplicity and ability to perform well make it an attractive choice.

Despite the development of more advanced sorting algorithms, insertion sort continues to be taught and studied as an important sorting technique. Its straightforward implementation and intuitive nature make it a valuable tool for learning sorting algorithms and understanding the fundamental principles of computer science.

### Algorithm for Insertion Sort

1. Start by defining the insertionSort function that takes an array arr and its size n as input.
2. Declare three variables: i, key, and j.
3. Iterate over the array starting from index 1 to n-1.
4. Assign the value of arr[i] to the variable key.
5. Assign the value of i-1 to j.
6. While j is greater than or equal to 0 and the value at arr[j] is greater than key, perform the following steps:
7. Assign the value of arr[j] to arr[j+1].
8. Decrement the value of j by 1.
9. Assign the value of key to arr[j+1].
10. Repeat steps 3-5 until the entire array is sorted.
11. Define the printArray function that takes an array arr and its size n as input.
12. Iterate over the array from index 0 to n-1.
13. Print the value of arr[i].
14. Print a new line to separate the output.
15. The sorting algorithm is complete.
16. To use the insertionSort function, you can call it from the main function and pass the array to be sorted along with its size. Similarly, you can use the printArray function to display the sorted array.

### Below is the program for insertion sort algorithm in C++:

Output:

```5 6 11 12 13
............
Process executed in 1.11 seconds
Press any key to continue.
```

Explanation:

Here's a step-by-step explanation of the given code:

1. The code begins by including the necessary header files: <bits/stdc++.h> which includes most standard library headers and using namespace std; which allows the usage of standard library functions and objects without explicitly specifying the namespace.
2. The insertionSort function is defined, which takes an array arr and its size n as parameters. This function implements the insertion sort algorithm to sort the array in ascending order.
3. Inside the insertionSort function, a loop iterates from the second element (i = 1) to the last element of the array. Each iteration represents selecting an element to be inserted into the sorted subarray.
4. The selected element is stored in the variable key. The variable j is set to the index of the element just before the selected element.
5. A while loop checks if the element at index j is greater than the key and if j is within the valid range (greater than or equal to 0). This loop shifts the elements greater than the key one position to the right.
6. After finding the correct position for the key element, it is inserted at j + 1 index in the array.
7. The printArray function is defined to print the elements of the array arr of size n in a space-separated format.
8. The main function is the entry point of the program. It initializes an array arr with values {12, 11, 13, 5, 6}.
9. The variable N is assigned the size of the array arr by dividing the total size of the array by the size of a single element.
10. The insertionSort function is called with arr and N as arguments to sort the array.
11. The printArray function is called to display the sorted array.
12. Finally, the main function returns 0, indicating successful execution of the program.
13. The output is displayed as "5 6 11 12 13", which represents the sorted array.
14. Overall, the code demonstrates the implementation of the insertion sort algorithm and sorts the given array in ascending order.

Time Complexity Analysis:

The time complexity of the Insertion Sort algorithm implemented in this code is O(n2) in the worst and average cases and O(n) in the best case.

The main loop runs for 0(n) iterations (where O(n) is the size of the array), and for each iteration, the inner while loop may run up to i times, where i is the current index in the outer loop. In the worst case, when the array is in reverse order, the inner loop will run its maximum number of times, resulting in O(n2) time complexity. In the best case, when the array is already sorted, the inner loop won't execute, and the time complexity is O(n).

Space Complexity Analysis:

The space complexity of the code is O(1). The reason is that the algorithm performs sorting in-place, without using any additional data structures whose space requirements depend on the input size. The only extra space used is for variables like i, key, and j, which are of constant size, regardless of the input array size.

In summary, the time complexity is O(n2) in the worst and average cases and O(n) in the best case, while the space complexity is O(1) as the algorithm uses a constant amount of extra space.

• Simplicity: Insertion sort is straightforward to understand and implement. It uses a simple comparison and swapping mechanism to sort the elements.
• Efficient for Small Inputs: Insertion sort performs well when the input size is small or the array is already partially sorted. It has relatively low overhead compared to more complex sorting algorithms.
• Online Sorting: Insertion sort is an online sorting algorithm, meaning it can efficiently handle data as it comes in one element at a time. This property makes it useful in scenarios where data is continuously being added or sorted dynamically.
• Space Efficiency: Insertion sort operates in-place, meaning it doesn't require additional memory to perform the sorting. It sorts the elements within the existing array itself.

• Quadratic Time Complexity: Insertion sort has an average and worst-case time complexity of O (n^2), making it inefficient for large input sizes. As the number of elements increases, the number of comparisons and shifts required grows exponentially.
• Lack of Adaptiveness: Insertion sort does not adapt well to already sorted or nearly sorted arrays. It still performs a full set of comparisons and shifts, even if the array is partially sorted.
• Not Suitable for Large Data Sets: Due to its quadratic time complexity, insertion sort becomes impractical for sorting large data sets. Other sorting algorithms such as merge sort or quicksort are more efficient in such scenarios.
• Performance Dependency on Input Order: The efficiency of insertion sort heavily depends on the initial order of the elements. If the array is reverse sorted, insertion sort will require the maximum number of comparisons and shifts, further increasing its time complexity.

In summary, while insertion sort has simplicity, space efficiency, and performs well on small inputs or partially sorted arrays, its quadratic time complexity and lack of adaptiveness make it less suitable for large data sets or already sorted arrays. Consider the characteristics of the input data and the desired performance requirements when choosing a sorting algorithm.

## Applications of Insertion Sort

Insertion sort is a simple yet efficient sorting algorithm that can be applied to various scenarios. Here are some common applications of insertion sort:

• Small Data Sets: Insertion sort performs well on small data sets or arrays that are already partially sorted or nearly sorted. It has a relatively low overhead and performs efficiently for such cases.
• Online Sorting: Insertion sort is often used for sorting data in real-time or as it becomes available. It allows for incremental sorting, where new elements can be efficiently inserted into a sorted list.
• Partial Sorting: In some scenarios, only a portion of the data needs to be sorted. Insertion sort is effective in such cases as it can sort a small part of the data while leaving the remaining elements untouched.
• Auxiliary Sorting Algorithm: Insertion sort is frequently used as an auxiliary algorithm within other sorting algorithms. For example, in algorithms like QuickSort or Timsort, insertion sort is used for sorting small subarrays or as a fallback when the array size becomes small.
• Educational Purposes: Due to its simplicity and ease of understanding, insertion sort is commonly taught in computer science and programming courses. It serves as a fundamental example of a sorting algorithm and helps students grasp the basic concepts of sorting.
• Optimized for Linked Lists: Insertion sort is well-suited for sorting linked lists because it requires only constant extra space. It efficiently rearranges the links between the nodes, making it a practical choice for sorting linked data structures.

Overall, insertion sort may not be the most efficient sorting algorithm for large-scale or highly unsorted data sets. However, its simplicity, suitability for specific scenarios, and educational value make it a valuable algorithm in various applications.