排序演算法3——圖解直接插入排序以及折半(二分)插入排序及其實現
阿新 • • 發佈:2018-12-16
排序演算法1——圖解氣泡排序及其實現(三種方法,基於模板及函式指標)
排序演算法2——圖解簡單選擇排序及其實現
排序演算法3——圖解直接插入排序以及折半(二分)插入排序及其實現
排序演算法4——圖解希爾排序及其實現
排序演算法5——圖解堆排序及其實現
排序演算法6——圖解歸併排序及其遞迴與非遞迴實現
排序演算法7——圖解快速排序以及不同CUTOFF的時間測試
一、直接插入的基本思想
將待排序的一組序列分為已排好序和未排好序的兩個部分
初始狀態時,已排好序序列僅包含第一個元素,未排好序的序列元素為除去第一個以外的n-1
個元素
然後,將未排好序序列中的元素逐一插入到已排好序的序列中
如此往復,經過n-1次插入後,未排序序列中的元素個數變為0,排序完成。如下圖所示
程式碼及上下界如圖
從程式碼可以看出,空間複雜度上,簡單插入排序僅需要常數個額外空間
在時間複雜度上,函式中有兩個巢狀的迴圈,每個迴圈進行O(N)
次比較和交換,故時間複雜度為O(N^2)
此外,簡單插入排序是穩定的排序,
可以在下面的具體過程中看到,數值相同的兩個記錄不會發生相對位置上的改變
具體過程
後面就不列出了
二、折半(二分)插入排序
雖然它的時間複雜度也是
O(N^2)
,但由於引用了二分的思想,它的平均效能會比直接插入好
總的來說,插入法比冒泡法和簡單選擇排序法的效能好一些
三、測試結果及程式碼
#include <iostream>
template<class T>
void InsertSort(T *a, int length) {
T tmp;
int i, j;
for (i = 1; i < length; ++i) {
tmp = a[i];
for (j = i; j > 0 && a[j - 1] > tmp; --j) {
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
template<class T>
void BinaryInsertSort(T *a, int length) {
int left, right, mid;
int tmp;
for (int i = 1; i < length; i++) {
/* 找到陣列中第一個無序的數,儲存為tmp */
if (a[i] < a[i - 1]) {
tmp = a[i];
}
else {
continue;
}
/* 找到陣列中第一個無序的數,儲存為tmp */
/* 二分查詢開始 */
left = 0;
right = i - 1;
while (left <= right) {
mid = (left + right) / 2;
if (a[mid] > tmp) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
/* 二分查詢結束,此時a[left]>=a[i],記錄下left的值 */
/* 將有序陣列中比要插入的數大的數右移 */
for (int j = i; j > left; j--) {
a[j] = a[j - 1];
}
/* 將有序陣列中比要插入的數大的數右移 */
// 將left位置賦值為要插入的數
a[left] = tmp;
}
}
template<class T>
void ArrShow(T *a, int length) {
for (int i = 0; i < length; ++i) {
std::cout << a[i] << " ";
}
puts("\n");
}
int main(int argc, char *argv[]) {
int test[9] = { 9, 1, 5, 8, 3, 7, 4, 6, 2 };
ArrShow(test, 9);
puts("InsertSort : ");
InsertSort(test, 9);
ArrShow(test, 9);
int test1[9] = { 9, 1, 5, 8, 3, 7, 4, 6, 2 };
puts("BinaryInsertSort : ");
BinaryInsertSort(test1, 9);
ArrShow(test1, 9);
return 0;
}