mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-03-22 05:55:42 -05:00
373 lines
7.8 KiB
Markdown
373 lines
7.8 KiB
Markdown
---
|
|
date: 2024-12-24
|
|
---
|
|
# Understanding Binary Insertion Sort
|
|
Binary Insertion Sort is a sorting algorithm that combines [[Insertion Sort]] with Binary Search for finding the location where an element should be inserted.
|
|
|
|
## Implementation
|
|
|
|
```cpp
|
|
void binaryInsertionSort(int arr[], int size)
|
|
{
|
|
int key;
|
|
int sortedIndex;
|
|
int insertionIndex;
|
|
|
|
for (int i = 1; i < size; i++)
|
|
{
|
|
key = arr[i];
|
|
sortedIndex = i - 1;
|
|
insertionIndex = binarySearch(arr, key, 0, sortedIndex);
|
|
|
|
for (int j = sortedIndex; j >= insertionIndex; j--)
|
|
arr[j + 1] = arr[j];
|
|
|
|
arr[insertionIndex] = key;
|
|
}
|
|
}
|
|
```
|
|
|
|
Where:
|
|
- `arr` is the array to be sorted
|
|
- `size` is the number of elements in the array
|
|
- `key` is the selected element in the unsorted portion of the array
|
|
- `sortedIndex` is the reverse index of the sorted portion of the array
|
|
- `insertionIndex` is the position to insert the `key` into the sorted portion of the array
|
|
|
|
### Binary Search Implementation
|
|
The different between the original binary search and the binary dearch used here is that its purpose is to find the correct position to insert the **key** value into the sorted array
|
|
|
|
```cpp
|
|
int binarySearch(int arr[], int key, int low, int high)
|
|
{
|
|
if (high <= low)
|
|
return (key > arr[low] ? low + 1 : low);
|
|
|
|
int mid = (low + high) / 2;
|
|
|
|
if (key == arr[mid])
|
|
return (mid + 1);
|
|
|
|
if (key > arr[mid])
|
|
return (binarySearch(arr, key, mid + 1, high));
|
|
|
|
return (binarySearch(arr, key, low, mid - 1));
|
|
}
|
|
```
|
|
|
|
where:
|
|
- `arr` is the sorted array in which to search
|
|
- `key` is the value to search for
|
|
- `low` is the lower bound index of the current search range
|
|
- `high` is the higher bound index of the current search range
|
|
|
|
Consider the following array $A$ with 3 elements $(n = 3)$:
|
|
$$
|
|
A = [6, 5, 3]
|
|
$$
|
|
### Step by step
|
|
Consider the following `for` loop that is the main part of the algorithm:
|
|
|
|
```cpp
|
|
for (int i = 1; i < size; i++)
|
|
{
|
|
key = arr[i];
|
|
sortedIndex = i - 1;
|
|
insertionIndex = binarySearch(arr, key, 0, sortedIndex);
|
|
|
|
for (int j = sortedIndex; j >= insertionIndex; j--)
|
|
arr[j + 1] = arr[j];
|
|
|
|
arr[insertionIndex] = key;
|
|
}
|
|
```
|
|
|
|
---
|
|
#### First Iteration
|
|
|
|
Values:
|
|
|
|
```
|
|
key = 5
|
|
i = 1
|
|
sortedIndex = 0
|
|
insertionIndex = ?
|
|
```
|
|
|
|
Those are the initial values for the first iteration. Now, to know where to insert the key into the sorted portion of the array, we need to call `binarySearch()`:
|
|
|
|
```cpp
|
|
for (int i = 1; i < size; i++)
|
|
{
|
|
key = arr[i];
|
|
sortedIndex = i - 1;
|
|
> insertionIndex = binarySearch(arr, key, 0, sortedIndex);
|
|
|
|
for (int j = sortedIndex; j >= insertionIndex; j--)
|
|
arr[j + 1] = arr[j];
|
|
|
|
arr[insertionIndex] = key;
|
|
}
|
|
```
|
|
|
|
##### Inside `binarySearch()`:
|
|
|
|
Values:
|
|
|
|
```
|
|
key = 5
|
|
low = 0
|
|
high = 0
|
|
```
|
|
|
|
As soon as we enter the function, the condition is met as $h \leq l$, so we enter the `return` statement. In this section the `key` gets compared with the first element of the array. As $5 \nleq 6$, `low` gets returned.
|
|
|
|
```cpp
|
|
if (high <= low)
|
|
> return (key > arr[low] ? low + 1 : low);
|
|
|
|
int mid = (low + high) / 2;
|
|
|
|
if (key == arr[mid])
|
|
return (mid + 1);
|
|
|
|
if (key > arr[mid])
|
|
return (binarySearch(arr, key, mid + 1, high));
|
|
|
|
return (binarySearch(arr, key, low, mid - 1));
|
|
```
|
|
|
|
##### Back to `binaryInsertionSort()`:
|
|
|
|
Now, we got to know the value for the `insertionIndex`:
|
|
|
|
```
|
|
key = 5
|
|
i = 1
|
|
sortedIndex = 0
|
|
insertionIndex = 0
|
|
```
|
|
|
|
Back to the execution, we find a for loop that goes through the sorted portion of the array in reverse order:
|
|
|
|
```cpp
|
|
for (int i = 1; i < size; i++)
|
|
{
|
|
key = arr[i];
|
|
sortedIndex = i - 1;
|
|
insertionIndex = binarySearch(arr, key, 0, sortedIndex);
|
|
|
|
> for (int j = sortedIndex; j >= insertionIndex; j--)
|
|
arr[j + 1] = arr[j];
|
|
|
|
arr[insertionIndex] = key;
|
|
}
|
|
```
|
|
|
|
In the first iteration, `j` gets the value of 0 and as $0 \geq 0$, we enter the loop.
|
|
Then, the array's element at index 1 gets the value of the array's element at index 0.
|
|
$$
|
|
A = [6, 6, 3]
|
|
$$
|
|
In the second iteration, `j` gets decremented to -1, breaking out of the loop. After that, the key is inserted at the index 0 of the array:
|
|
|
|
```cpp
|
|
for (int i = 1; i < size; i++)
|
|
{
|
|
key = arr[i];
|
|
sortedIndex = i - 1;
|
|
insertionIndex = binarySearch(arr, key, 0, sortedIndex);
|
|
|
|
for (int j = sortedIndex; j >= insertionIndex; j--)
|
|
arr[j + 1] = arr[j];
|
|
|
|
> arr[insertionIndex] = key;
|
|
}
|
|
```
|
|
|
|
Result:
|
|
$$
|
|
A = [5, 6, 3]
|
|
$$
|
|
---
|
|
#### Second Iteration
|
|
|
|
Values:
|
|
|
|
```
|
|
key = 3
|
|
i = 2
|
|
sortedIndex = 1
|
|
insertionIndex = ?
|
|
```
|
|
|
|
Now, we are going to enter `binarySearch()` again to retrieve the index for inserting the `key`:
|
|
##### Inside `binarySearch()`:
|
|
|
|
Values:
|
|
|
|
```
|
|
key = 3
|
|
low = 0
|
|
high = 1
|
|
```
|
|
|
|
The condition base condition is false as $1 \nleq 0$ so we go to the next line:
|
|
|
|
```cpp
|
|
> if (high <= low)
|
|
return (key > arr[low]) ? (low + 1) : low;
|
|
|
|
int mid = (low + high) / 2;
|
|
|
|
if (key == arr[mid])
|
|
return (mid + 1);
|
|
|
|
if (key > arr[mid])
|
|
return (binarySearch(arr, key, mid + 1, high));
|
|
|
|
return (binarySearch(arr, key, low, mid - 1));
|
|
```
|
|
|
|
The value for `mid` gets calculated resulting in 0:
|
|
|
|
```
|
|
key = 3
|
|
low = 0
|
|
high = 1
|
|
mid = 0
|
|
```
|
|
|
|
```cpp
|
|
if (high <= low)
|
|
return (key > arr[low]) ? (low + 1) : low;
|
|
|
|
> int mid = (low + high) / 2;
|
|
|
|
if (key == arr[mid])
|
|
return (mid + 1);
|
|
|
|
if (key > arr[mid])
|
|
return (binarySearch(arr, key, mid + 1, high));
|
|
|
|
return (binarySearch(arr, key, low, mid - 1));
|
|
```
|
|
|
|
Then, we check if the `key` is equal to `arr[mid]`. As $3 \neq 5$, we skip this line:
|
|
$$
|
|
A = [5, 6, 3]
|
|
$$
|
|
```cpp
|
|
if (high <= low)
|
|
return (key > arr[low]) ? (low + 1) : low;
|
|
|
|
int mid = (low + high) / 2;
|
|
|
|
> if (key == arr[mid])
|
|
return (mid + 1);
|
|
|
|
if (key > arr[mid])
|
|
return (binarySearch(arr, key, mid + 1, high));
|
|
|
|
return (binarySearch(arr, key, low, mid - 1));
|
|
```
|
|
|
|
After that, we check if the `key` is greater than the `arr[mid]`. As $3 \not> 5$m we go to the next line:
|
|
|
|
```cpp
|
|
if (high <= low)
|
|
return (key > arr[low]) ? (low + 1) : low;
|
|
|
|
int mid = (low + high) / 2;
|
|
|
|
if (key == arr[mid])
|
|
return (mid + 1);
|
|
|
|
if (key > arr[mid])
|
|
return (binarySearch(arr, key, mid + 1, high));
|
|
|
|
> return (binarySearch(arr, key, low, mid - 1));
|
|
```
|
|
|
|
Here, we recursively enter `binarySearch()` with the following values:
|
|
|
|
```
|
|
key = 3
|
|
low = 0
|
|
high = -1
|
|
```
|
|
|
|
As $-1 \leq 0$, we enter the base case. Inside it, the `key` which is 3 gets compared with `arr[0]` which is 5, as $3 \not> 5$, the value for `low`, 0 gets returned.
|
|
|
|
```cpp
|
|
> if (high <= low)
|
|
return (key > arr[low]) ? (low + 1) : low;
|
|
|
|
int mid = (low + high) / 2;
|
|
|
|
if (key == arr[mid])
|
|
return (mid + 1);
|
|
|
|
if (key > arr[mid])
|
|
return (binarySearch(arr, key, mid + 1, high));
|
|
|
|
return (binarySearch(arr, key, low, mid - 1));
|
|
```
|
|
|
|
##### Back to `binaryInsertionSort()`:
|
|
|
|
Now, we got to know the value for the `insertionIndex`:
|
|
|
|
```
|
|
key = 3
|
|
i = 2
|
|
sortedIndex = 1
|
|
insertionIndex = 0
|
|
```
|
|
|
|
Back to the execution, we find a for loop that goes through the sorted portion of the array in reverse order:
|
|
|
|
```cpp
|
|
for (int i = 1; i < size; i++)
|
|
{
|
|
key = arr[i];
|
|
sortedIndex = i - 1;
|
|
insertionIndex = binarySearch(arr, key, 0, sortedIndex);
|
|
|
|
> for (int j = sortedIndex; j >= insertionIndex; j--)
|
|
arr[j + 1] = arr[j];
|
|
|
|
arr[insertionIndex] = key;
|
|
}
|
|
```
|
|
|
|
In the first iteration, `j` gets the value of 1 and as $1 \geq 0$, we enter the loop.
|
|
Then, the array's element at index 2 gets the value of the array's element at index 1.
|
|
$$
|
|
A = [5, 6, 6]
|
|
$$
|
|
`j` gets decremented to 0 and the condition is checked again. It checks as true as $0 \geq 0$. Then, inside the loop, the array's second element gets the value of the array's first element.
|
|
$$
|
|
A = [5, 5, 6]
|
|
$$
|
|
`j` gets decremented to -1 and we break out of the loop as $-1 \ngeq 0$. After that, the key is inserted at the `insertionIndex` position in the array:
|
|
|
|
```cpp
|
|
for (int i = 1; i < size; i++)
|
|
{
|
|
key = arr[i];
|
|
sortedIndex = i - 1;
|
|
insertionIndex = binarySearch(arr, key, 0, sortedIndex);
|
|
|
|
for (int j = sortedIndex; j >= insertionIndex; j--)
|
|
arr[j + 1] = arr[j];
|
|
|
|
> arr[insertionIndex] = key;
|
|
}
|
|
```
|
|
|
|
Result:
|
|
$$
|
|
A = [3, 5, 6]
|
|
$$
|