直接插入排序法:

//arr表示待排序的数组,length表示数组的长度
void InsertSort(int arr[], int length)
{
	int i, j;
	//arr[0]直接插入排序的序列中,故从i=1开始排
	//外部更替
	for (i = 1; i < length; i++)
	{
		//先通过比较判断arr[i]是否是一个较小值
		if (arr[i] < arr[i - 1])
		{
			//先保存arr[i]的值
			int temp = arr[i];
			//内部比较并移动
			for (j = i - 1; j >= 0; j--)
			{
				if (temp < arr[j])
				{
					arr[j + 1] = arr[j]; //每次比较后,arr[j]都往后退一步
				}
				else
				{
					//如果temp已经找到自己的合适位置,那么退出循环
					break;
				}
			}
			//因为j指向的是比temp还小的元素,故temp应该排在j+1这个位置
			arr[j + 1] = temp;
		}
	}
}

折半插入排序法是由直接插入法改进而来的:主要改进的地方就是查找部分,通过折半查找法快速找到合适的插入位置。

折半插入排序法:

void BInsertSort(int arr[],int length)
{
	int i;
	for (i = 1; i < length; i++)
	{
		int temp = arr[i];
		int high = i - 1;
		int low = 0;
		//通过折半查找法找到适合temp的位置
		while (low<=high)//当查找区间只剩下一个元素时,必定有 low=high
		{
			//当low=high时,经过以下程序,必有low比high大1
			int mid = (high + mid) / 2;
			if (temp < arr[mid])
			{
				high = mid - 1;
			}
			else
			{
				low = mid + 1;
			}
		}
		//经过折半查找以后,high必定比low小1,即  low=high+1;
		//而插入元素的位置必然是low或high+1(因为low==high+1)
		//然后移动元素,为temp空出位置
		int j;
		for (j = i - 1; j >= low; j--)
		{
			arr[j + 1] = arr[j];
		}
		arr[low] = temp;

	}
}

希尔排序法也是经过直接插入法改进而来的,其本质就是多重插入排序,效率提升的原因是本来较小的元素需要挨个移动,而希尔排序直接跨越移动,减少了元素的移动次数。故希尔排序相较于直接插入排序,其改进的地方就是移动元素的部分。当希尔增量等于1的时候,就是直接插入排序法,但是经过之前多轮不同增量下的插入排序,最后一轮排序时,整个数组已经变得相对有序很多了。

希尔排序法:

void ShellSort(int arr[], int length)
{
	int inc; //希尔增量
	//这里采用朴素希尔增量,即每次增量都是上一次的一半
	for (inc = length / 2; inc >= 1; inc = inc / 2)
	{
		//这里i=inc,就好比直接插入排序中的i=1一样,都是第一个元素首先直接插入
        //这里的循环条件依旧是i<length,希尔增量只是使每轮比较的元素个数减少,
        //而不会使外部的更替次数减少
		for (int i = inc; i < length; i++)
		{
			//加上个if语句使效率更高,当arr[i]>arr[i-inc]时直接开始下轮循环
			//但是去掉if判断也不影响结果
			if (arr[i] < arr[i - inc])
			{
				//temp首先记录arr[i]的值
				int temp = arr[i];
				int j;
				//比较并移动元素
				for (j = i - inc; j >= 0 && temp < arr[j]; j = j - inc)
				{
					arr[j + inc] = arr[j];
				}
				//j指向的元素必定小于等于temp,故yemp插入的位置为j+inc
				arr[j + inc] = temp;
			}
		}
	}
}