Insertion sort is a simple and efficient sorting algorithm that works by dividing the input into a sorted and an unsorted region. It repeatedly takes an element from the unsorted region and inserts it into its correct position in the sorted region. This process continues until the entire array is sorted.

One of the key advantages of insertion sort is its simplicity. The algorithm is easy to understand and implement, making it a popular choice for small to medium-sized datasets. It also performs well when the input is already partially sorted or nearly sorted, as it requires fewer comparisons and swaps compared to other sorting algorithms.

Insertion sort has a time complexity of O(n^2), where n is the number of elements in the input array. This means that the algorithm’s performance degrades quickly as the size of the input increases. However, for small datasets or when efficiency is not a major concern, insertion sort can be a practical choice.

Another advantage of insertion sort is its stability. A sorting algorithm is considered stable if it preserves the relative order of elements with equal keys. In other words, if two elements have the same key, their order in the sorted array should be the same as their order in the original array. Insertion sort maintains the stability property, making it useful in certain scenarios where preserving the order of equal elements is important.

Despite its advantages, insertion sort does have some limitations. As mentioned earlier, its time complexity is relatively high compared to other sorting algorithms such as merge sort or quicksort. This makes it less suitable for large datasets or time-sensitive applications. Additionally, insertion sort is an in-place sorting algorithm, meaning it does not require additional memory beyond the input array. However, it is not a stable in-place sorting algorithm, as it may require swapping elements to maintain the correct order.

In conclusion, insertion sort is a simple and efficient sorting algorithm that works by dividing the input into a sorted and an unsorted region. Although it may not be the most efficient choice for large datasets, it offers simplicity, stability, and practicality for smaller datasets or when efficiency is not a major concern. Its ease of implementation and ability to handle partially sorted input make it a valuable tool in the realm of sorting algorithms.

Once the insertion sort algorithm has iterated through the entire array and made the necessary swaps, it moves on to the next element and repeats the process. This continues until all elements in the array are in their correct sorted positions.

One advantage of insertion sort is that it performs well on small arrays or partially sorted arrays. Since it only compares adjacent elements and swaps them if necessary, it has a relatively low time complexity of O(n^2). However, this also means that insertion sort can be quite slow on larger arrays or arrays that are completely unsorted.

Another advantage of insertion sort is that it is an in-place sorting algorithm, meaning it does not require additional memory to sort the array. It simply rearranges the elements within the array itself. This can be beneficial in situations where memory is limited or when sorting large datasets.

However, despite its advantages, insertion sort is not the most efficient sorting algorithm available. As mentioned earlier, its time complexity is O(n^2), which means that its performance decreases significantly as the size of the array increases. For larger datasets, more efficient sorting algorithms such as merge sort or quicksort are often preferred.

Despite its limitations, insertion sort still has its uses. It can be a good choice when dealing with small arrays or partially sorted arrays, as it can perform well in these scenarios. Additionally, it is a simple algorithm to implement and understand, making it a good choice for educational purposes or when simplicity is prioritized over efficiency.

In conclusion, the insertion sort algorithm works by comparing each element with the elements that come before it and swapping them if necessary. It continues this process until all elements are in their correct sorted positions. While insertion sort has a relatively low time complexity and is an in-place sorting algorithm, it is not the most efficient option for large or unsorted arrays. However, it can still be a useful algorithm in certain scenarios and is a good choice for educational purposes or when simplicity is prioritized.

Now, let’s go step by step through the process of insertion sort to see how it works on this array.

First, we start with the first element of the array, which is 7. Since it is the only element in the sorted portion of the array, we can consider it already sorted.

Next, we move on to the second element, which is 2. We compare it with the element before it, which is 7. Since 2 is smaller than 7, we swap their positions, resulting in the array [2, 7, 5, 1, 9, 3]. Now, we have the first two elements in sorted order.

Next, we move on to the third element, which is 5. We compare it with the elements before it, which are 7 and 2. Since 5 is smaller than 7, we swap their positions, resulting in the array [2, 5, 7, 1, 9, 3]. Now, we have the first three elements in sorted order.

We continue this process for the remaining elements of the array. Next, we consider the element 1. We compare it with the elements before it, which are 7, 5, and 2. Since 1 is smaller than all of them, we swap their positions, resulting in the array [1, 2, 5, 7, 9, 3]. Now, we have the first four elements in sorted order.

Next, we consider the element 9. We compare it with the elements before it, which are 7, 5, and 2. Since 9 is greater than all of them, we leave it in its position. The array remains unchanged: [1, 2, 5, 7, 9, 3]. Now, we have the first five elements in sorted order.

Finally, we consider the last element, which is 3. We compare it with the elements before it, which are 9, 7, 5, and 2. Since 3 is smaller than all of them, we swap their positions, resulting in the final sorted array: [1, 2, 3, 5, 7, 9].

As we can see, insertion sort works by repeatedly inserting an element into its correct position in a sorted portion of the array. It is an efficient sorting algorithm for small arrays or partially sorted arrays, but it can be slow for large arrays or arrays with a random order of elements.

## Step 1:

Start with the second element, which is 2. Compare it with the first element, which is 7. Since 2 is smaller than 7, we swap them.

The array becomes: [2, 7, 5, 1, 9, 3].

Now, we move on to the next element, which is 5. We compare it with the previous element, which is 7. Since 5 is smaller than 7, we swap them.

The array becomes: [2, 5, 7, 1, 9, 3].

Next, we move on to the next element, which is 1. We compare it with the previous element, which is 7. Since 1 is smaller than 7, we swap them.

The array becomes: [2, 5, 1, 7, 9, 3].

We continue this process until we reach the end of the array. At each step, we compare the current element with the previous element and swap them if necessary. This process is repeated until the entire array is sorted in ascending order.

After completing the first step, the array now looks like this: [2, 5, 1, 7, 9, 3]. We have successfully moved the smallest element, which was 1, to its correct position at the beginning of the array.

Now, we move on to the next step of the sorting algorithm, which involves repeating the same process for the remaining elements. We start with the second element again and compare it with the previous element, swapping them if necessary. This process is repeated until the entire array is sorted.

Now that we have swapped the elements 7 and 5, we move on to the next element in the array, which is 1. We compare it with the previous element, which is 7. Since 1 is smaller than 7, we swap them.

The array becomes: [2, 5, 1, 7, 9, 3].

Next, we move on to the element 9 and compare it with the previous element, which is 7. Since 9 is greater than 7, we do not need to swap them.

The array remains: [2, 5, 1, 7, 9, 3].

Now, we move on to the element 3 and compare it with the previous element, which is 9. Since 3 is smaller than 9, we swap them.

The array becomes: [2, 5, 1, 7, 3, 9].

At this point, we have gone through the entire array and made necessary swaps to ensure that each element is in its correct position relative to the previous element. However, we may need to repeat this process multiple times to completely sort the array.

Let’s continue with the next step to further sort the array.

## Step 4:

Now that we have compared and swapped the first element with all the elements before it, we move on to the next element in the array, which is 2. We compare it with the previous element, which is 1. Since 2 is greater than 1, we do not need to swap them. The array remains the same: [1, 2, 5, 7, 9, 3].

Next, we compare 5 with 2. Since 5 is greater than 2, we do not need to swap them. The array remains the same: [1, 2, 5, 7, 9, 3].

Then, we compare 7 with 5. Since 7 is greater than 5, we do not need to swap them. The array remains the same: [1, 2, 5, 7, 9, 3].

After that, we compare 9 with 7. Since 9 is greater than 7, we do not need to swap them. The array remains the same: [1, 2, 5, 7, 9, 3].

Finally, we compare 3 with 9. Since 3 is smaller than 9, we swap them.

The array becomes: [1, 2, 5, 7, 3, 9].

Now, we have completed the second iteration of the bubble sort algorithm. The largest element, which is 9, has moved to its correct position at the end of the array. We will continue with the next iteration to sort the remaining elements.

## Step 5:

Now, we move on to the next element in the array, which is 3. We compare it with the previous element, which is 9. Since 3 is smaller than 9, we need to swap them.

The array becomes: [1, 2, 5, 7, 3, 9].

At this point, we have completed the first iteration of the outer loop. The largest element, which is 9, has been moved to its correct position at the end of the array. Now, we need to repeat the process for the remaining elements in the array.

So, we start again from the beginning of the array and compare each element with its adjacent element. If the current element is smaller than the previous element, we swap them. This process is repeated until we reach the end of the array.

Let’s continue with the next iteration:

## Step 6:

We start with the first element, which is 1, and compare it with the next element, which is 2. Since 1 is smaller than 2, we leave them as they are.

The array remains: [1, 2, 5, 7, 3, 9].

Next, we compare 2 with 5. Since 2 is smaller than 5, we leave them as they are.

The array remains: [1, 2, 5, 7, 3, 9].

We continue this process for the remaining elements in the array until we reach the end.

Let’s move on to the next iteration:

## Step 6:

We start with the first element, which is 1, and compare it with the next element, which is 2. Since 1 is smaller than 2, we leave them as they are.

The array remains: [1, 2, 5, 7, 3, 9].

Next, we compare 2 with 5. Since 2 is smaller than 5, we leave them as they are.

The array remains: [1, 2, 5, 7, 3, 9].

We continue this process for the remaining elements in the array until we reach the end.

Let’s move on to the next iteration:

## Step 7:

We start with the first element, which is 1, and compare it with the next element, which is 2. Since 1 is smaller than 2, we leave them as they are.

The array remains: [1, 2, 5, 7, 3, 9].

Next, we compare 2 with 5. Since 2 is smaller than 5, we leave them as they are.

The array remains: [1, 2, 5, 7, 3, 9].

We continue this process for the remaining elements in the array until we reach the end.

This process of comparing and swapping elements is repeated until the array is sorted in ascending order.

Let’s continue with the next iteration:

## Step 6:

Now that we have compared and swapped all the necessary elements, we move on to the next iteration of the outer loop. This time, we start comparing elements from the beginning of the array again.

The first element we encounter is 1. We compare it with the next element, which is 2. Since 1 is smaller than 2, we don’t need to swap them.

We continue comparing 2 with the next element, which is 3. Again, 2 is smaller than 3, so we don’t swap them.

Next, we compare 3 with 5. Once again, 3 is smaller than 5, so no swapping is required.

Then, we compare 5 with 7. Since 5 is smaller than 7, we don’t need to swap them.

Finally, we compare 7 with 9. As expected, 7 is smaller than 9, so no swapping is needed.

At this point, we have completed the second iteration of the outer loop. The array remains unchanged: [1, 2, 3, 5, 7, 9].

We continue this process for the remaining iterations of the outer loop until no more swaps are needed. This indicates that the array is fully sorted in ascending order.

It’s important to note that the number of iterations required by the outer loop is equal to the number of elements in the array minus one. This is because after each iteration, the largest element is guaranteed to be in its correct position at the end of the array.

Once the outer loop completes its iterations, we can confidently say that the array is sorted. In this case, the final sorted array is [1, 2, 3, 5, 7, 9].

Now that we have completed the last iteration of the sorting algorithm, let’s take a moment to review the final state of the array. The array currently contains the elements [1, 2, 3, 5, 7, 9].

At this point, we can confidently say that the array is sorted in ascending order. This means that the elements are arranged from the smallest to the largest value. The sorting algorithm we used, known as bubble sort, has successfully rearranged the elements to achieve this desired outcome.

Bubble sort is a simple and intuitive sorting algorithm that works by repeatedly swapping adjacent elements if they are in the wrong order. In each iteration, the largest element “bubbles” to the end of the array, hence the name bubble sort. This process is repeated until the entire array is sorted.

Although bubble sort is easy to understand and implement, it is not the most efficient sorting algorithm. Its time complexity is O(n^2), meaning that the number of comparisons and swaps grows exponentially with the size of the array. As a result, bubble sort is not recommended for large datasets.

However, bubble sort does have its advantages. It is a stable sorting algorithm, meaning that elements with equal values retain their relative order after sorting. Additionally, bubble sort requires minimal additional memory, as it only needs to store a few variables to keep track of the iterations and swaps.

Overall, bubble sort is a good algorithm to use when sorting small arrays or when simplicity and ease of implementation are more important than efficiency. It serves as a great introduction to the concept of sorting algorithms and can help build a foundation for understanding more complex sorting techniques.

## Final Sorted Array:

The final sorted array using insertion sort is: [1, 2, 3, 5, 7, 9].

Now that we have successfully applied the insertion sort algorithm to the given array, let’s take a closer look at how it works. Insertion sort is a simple and efficient sorting algorithm that works by dividing the array into two parts: a sorted part and an unsorted part. Initially, the sorted part contains only the first element of the array, while the rest of the elements are considered unsorted.

To sort the array, insertion sort iterates through the unsorted part and compares each element with the elements in the sorted part. If an element in the unsorted part is smaller than the element in the sorted part, it is inserted into its correct position in the sorted part. This process continues until all elements in the unsorted part have been inserted into the sorted part.

In our example, the initial array was [3, 1, 7, 2, 9, 5]. Let’s go through the steps of the insertion sort algorithm to see how it sorted the array:

1. First, we start with the first element of the array, which is 3. Since it is the only element in the sorted part, the array remains unchanged.

2. Next, we move to the second element, which is 1. We compare it with the element in the sorted part, which is 3. Since 1 is smaller than 3, we shift 3 to the right and insert 1 into the correct position in the sorted part. The array now becomes [1, 3, 7, 2, 9, 5].

3. We continue this process with the third element, which is 7. We compare it with the elements in the sorted part, which are 1 and 3. Since 7 is greater than both 1 and 3, it remains in its current position. The array remains unchanged: [1, 3, 7, 2, 9, 5].

4. Moving on to the fourth element, which is 2. We compare it with the elements in the sorted part, which are 1, 3, and 7. Since 2 is smaller than 7, we shift 7 to the right and insert 2 into the correct position in the sorted part. The array now becomes [1, 2, 3, 7, 9, 5].

5. Next, we look at the fifth element, which is 9. We compare it with the elements in the sorted part, which are 1, 2, 3, and 7. Since 9 is greater than all of them, it remains in its current position. The array remains unchanged: [1, 2, 3, 7, 9, 5].

6. Finally, we consider the last element, which is 5. We compare it with the elements in the sorted part, which are 1, 2, 3, 7, and 9. Since 5 is smaller than 9, we shift 9 to the right and insert 5 into the correct position in the sorted part. The array now becomes [1, 2, 3, 5, 7, 9].

After going through all the elements in the array, we have successfully sorted it in ascending order using the insertion sort algorithm. The final sorted array is [1, 2, 3, 5, 7, 9].

Insertion sort has a time complexity of O(n^2), making it efficient for small arrays or partially sorted arrays. However, it can be slower than other sorting algorithms like merge sort or quicksort for larger arrays. Nonetheless, insertion sort is still widely used in practice due to its simplicity and effectiveness for certain types of data.

Although the time complexity of insertion sort is O(n^2), it is important to note that this worst-case scenario is not always encountered. In fact, under certain conditions, insertion sort can perform significantly better than other sorting algorithms.

One of the factors that can affect the performance of insertion sort is the initial order of the elements in the array. If the array is already partially sorted or nearly sorted, insertion sort can take advantage of this and complete the sorting process in linear time, resulting in a best-case time complexity of O(n).

Another factor that can impact the efficiency of insertion sort is the size of the array. For small arrays or arrays with a small number of elements, the overhead of other sorting algorithms, such as merge sort or quicksort, can outweigh their advantages. In these cases, insertion sort can be a more efficient choice, even with its O(n^2) time complexity.

Furthermore, insertion sort has a relatively low constant factor compared to other sorting algorithms. This means that, in practice, insertion sort can outperform algorithms with better theoretical time complexity, such as bubble sort or selection sort, for small or partially sorted arrays.

It is worth mentioning that insertion sort is an in-place sorting algorithm, meaning that it does not require additional memory beyond the original array. This can be advantageous in situations where memory is limited or when sorting large datasets.

Overall, while the time complexity of insertion sort may be O(n^2) in the worst case, its performance can be influenced by various factors such as the initial order of the elements and the size of the array. In certain scenarios, insertion sort can be a practical and efficient choice for sorting arrays.