排序演算法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;
}