排序算法(一) 插入排序和希尔排序

本文详细介绍直接插入排序和希尔排序两种排序算法。直接插入排序通过逐步插入元素并调整位置实现排序;希尔排序则通过分组并逐步减少增量进行排序。文章还提供了算法的时间复杂度和稳定性分析。

本篇博客介绍的是排序算法(一) 插入排序:直接插入排序和希尔排序

 插入排序的思想:在一个已排好序的记录子集的基础上,每一步将下一个待排序的记录语序插入到已排好序的记录子集中,直到将所有待排记录全部插入为止。

一、直接插入排序

 直接插入排序是一种最基本的插入排序方法,其基本操作是将第i个记录插入到前面i-1个已排好的记录中。

 直接插入排序的思想:将第i个元素的关键字Ki,顺次与前面记录的关键字进行比较,将大于关键字Ki的元素依次向后移动一个位置,直到遇到一个小于或等于的Ki的元素Kj,此时Kj后面必定是一个空位置,将i元素插入即可。

直接插入排序的思路:完整的直接插入排序是从i=1开始,也就是将第一个记录视为已排好序的单元素子集和,然后将第二个元素记录插入到单元素子集和中。i从2循环到n,即可实现完整的直接插入排序。

 (1)使用监视哨temp = r[i] ,保存待插入的记录,

 (2)比较元素,找到插入的位置并搬移元素(第一次从i=1开始,)

 (3) 将元素插入位置

代码: 升序排序

void InsertSort(int array[], size_t size) //升序
{
	for (size_t i = 1; i < size; ++i)
	{
		int temp = array[i];
		int pos = i - 1;
		while (pos >= 0 && array[pos] > temp) //小心数组越界
		{
			array[pos + 1] = array[pos];//搬移元素
			--pos;
		}
		array[pos + 1] = temp;
	}
}

算法分析:

空间复杂度:它只需要一个辅助空间,所以空间复杂度为O(1)

时间复杂度:主要时间耗费在比较和搬移元素上。

对于一趟插入排序,算法的while循环的次数取决于待插入记录与前i-1个记录的关系上

最好的情况(顺序):while循环只执行一次,且不移动

最坏的情况(逆序):while循环中关键字比较和移动记录的次数为i-1.

时间复杂度为T(n) = O(n^2)

稳定性:直接插入排序是稳定的,由于while循环判断条件array[pos] >temp保证了后面出现的关键字不可能插入到前面与之相同的关键字之前。

二、折半插入排序

基本思想:在上面插入排序的基础上,在while循环中比较时采用折半查找插入位置,性能优于顺序查找

 代码:

//在查找元素时 用二分查找来优化[]
void InsertSort_P(int arr[],size_t size)
{
	for (size_t idx = 1; idx < size; ++idx)
	{
		int temp = arr[idx];		
		int left = 0;
		int right = idx -1;
		int mid = 0;
		//查找插入的位置
		while (left <= right)
		{
			mid = left + ((right - left) >> 1);
			if (temp < arr[mid]) //相等的话,插入其后面
			{
				right = mid - 1;
			}
			else
			{
				left = mid + 1;			
			}
		}
		//跳出循环,left为插入的位置
		int pos = left;
		for (int index = idx -1; index >= pos ; --index)
		{
			arr[index + 1] = arr[index];
		}
		arr[pos] = temp;
	}
}

时间复杂度:O(n^2)


三、希尔排序(缩小增量排序算法)

基本思想:将待排序记录序列分割为若干个“较稀疏的”子序列,分别进行插入排序。

把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。
随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。

void ShellSort(int arr[],size_t size)
{
	int gsp = size;
	while (gsp > 1)
	{
		gsp = gsp / 3 + 1;
		for (size_t idx = gsp; idx < size; idx+=gsp)
		{
			int temp = arr[idx];
			int pos = idx - gsp;
			while (pos >= 0 && arr[pos] > temp)
			{
				//搬移,从后向前搬移
				arr[pos + gsp] = arr[pos];
				pos = pos - gsp;
			}
			arr[pos + gsp] = temp;
		}
		
	}
}

关于gsp的取法,最初希尔Shell提取出d = n/2,再取d=n/2,知道d=1;该思路的缺点,奇数位置的元素在最后一步才会与偶数位置进行比较,使得希尔排序效率降低。

时间复杂度:O(n^1.25)

稳定性:不稳定的。反例{2,4,1,2}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值