数据结构 第七章 排序——直接插入排序,折半插入排序,希尔排序

本文深入解析了直接插入排序、折半插入排序、希尔排序等算法,包括它们的空间与时间效率、稳定性及逆序对概念,提供了详细的算法实现代码,帮助读者理解排序算法的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接插入排序:

void Insert_Sort_Direct( ElementType a[], int n )
{
	int i, j;
	for( i = 1; i < n; i++ ){ //外部循环,此时假定a[0]是已经排好序的,所以把下标从1到n-1的数据依次插入序列中 
		int tmp = a[i];       //暂时存储要插入的元素 
		for( j = i; j > 0 && a[ j - 1 ] > tmp; j-- )  //内部循环,从当前位置开始向前比较,如果前面的元素大于待插入元素且前面还有元素 
			a[j] = a[ j - 1 ];                        //就把元素向后挪动,腾出位置 
		a[ j ] = tmp;         //把要插入的元素放进腾出的位置来 
	}
}

空间效率:只借助常数个辅助单元,空间复杂度为O(1);
时间效率:取决于待排序表的初始状态(只有操作有两步,一个是比较,一个是移动)。
最好情况:原始数据顺序排放,则每添加一个数据需要1次比较和0次挪动,所有对n个数据需要n次比较,此时时间复杂度为O(n)。
最坏情况:原始数据逆序排放,则每添加一个数据需要进行i次比较和i次移动(i为下标),所以完整的排序需要n(n - 1) / 2次比较和移动。
平均情况下需要n(n + 1) / 4次比较和移动,时间复杂度为O(n^2)。
稳定性:稳定。(因为总是从后向前比较发现比前面元素小才会移动,当元素相等时不会发生移动)。

折半插入排序:

void Insert_Sort_Binary( ElementType a[], int n )
{
	int i, j, low, high, mid;
	for( i = 1; i < n; i++ ){ //外部循环,此时假定a[0]是已经排好序的,所以把下标从1到n-1的数据依次插入序列中 
		int tmp = a[i];           //暂时存储要插入的元素
		low = 0;                  //设置下界为0 
		high = i - 1;             //设置上界为当前已排好序的最后一个元素的位置 
		while( low <= high ){     //默认排递增序列 
			mid = ( low + high ) / 2;   //取中间值 
			if( a[mid] < a[i] )         //如果要插入的元素比中间值大 
				low = mid + 1;          //说明应该插在中间值的右边,所以修改下界 
			else
				high = mid - 1;         //否则说明应该插在中间值的左边,所以修改上界 
		}
		for( j = i - 1; j >= high + 1; j-- )  //跳出循环时low大于high,此时high+1位置就是要插入的位置,所以循环移动元素腾出空位 
			a[j + 1] = a[j];
		a[ high + 1 ] = tmp;            //把待插入元素放进腾出来的位置 
	}
} 

这里理解之所以要在high+1位置插入,可以把折半查找最后的各种情况罗列出来,然后得到统一的结论,即待插入元素要放在high+1的位置,或者说放在low的位置。
时间复杂度:从两部分分析,第一部分是比较部分,采用折半插入算法,比较部分的时间复杂度为O(nlogn)(n个元素,每个需要logn),第二部分是移动部分,它依然取决于序列的初始状态,和直接插入排序算法的移动部分完全一样,也是O(n^2),所以总的时间复杂度也是O(n ^2)。
稳定性:稳定(原因与直接插入排序一样)。

逆序对(inversion):对于下标i < j,如果A[i] > A[j],则称( i, j )是一对逆序对。
时间复杂度下界:任意N个不同元素组成的序列平均有N(N - 1)/ 4个逆序对,如果仅靠交换相邻两元素来排序的算法(交换一次消去一个逆序对),其平均时间复杂度为O(n^2)。

希尔排序(缩小增量排序):

void Shell_Sort( ElementType a[], int n )
{
	int i, j, d;                       //d是步长 
	for( d = n / 2; d > 0; d /= 2 ){   //希尔增量序列,d每次等于上一次一半向下取整,最后一次d=1,结束之后跳出循环 
		for( i = d; i < n; i++ ){       
			int tmp = a[i];            //暂时存储要插入的元素
			for( j = i; j >= d && a[ j - d ] > tmp; j -= d )  //从后向前根据间隔进行比较和移动 
				a[j] = a[ j - d ];
			a[j] = tmp;                //把待插入元素放进腾出来的位置
		} 
	}
} 

空间效率:仅借助常数的辅助单元,所以空间复杂度为O(1)。
时间效率:最坏情况下O(n^2)(增量元素不互质,小增量可能根本不起作用)。
稳定性:不稳定。
还有一些其它的增量序列可以使算法的时间复杂度更小一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

房东的小黑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值