数据结构之插入排序

插入排序是一种简单直观的排序算法,基本思想是:将一个待排序的元素按其关键字大小插入到前面已排好序的子序列,直至全部记录插入完成。今天要介绍的就是三钟插入排序,直接插入排序,折半插入排序,希尔排序。

一、直接插入排序:

插入排序在是实现上通常采用原地排序,因此在从后往前的比较过程中,需要反复把已经排好序的逐步向后挪位,为新元素提供插入空间。

手动模拟过程:

括号里是已经排序好的子序列,哨兵是记录的待插入的元素,有序的序列中是从后往前和哨兵进行比较的。

具体代码:

/*对顺序表L做直接插入排序 一边比较一边移动*/
void InsertSort(SqList *L)
{
	int i,j;
	/*从第二个开始,将A[2]~A[n]插入前面已排序序列*/ 
	for(int i=2;i<=L->length;i++)
	{
		if(L->r[i]<L->r[i-1])
		{
			L->r[0]=L->r[i];//设置i位置为哨兵
			for(j=i-1;L->r[j]>L->r[0];j--)
			{
				L->r[j+1]=L->r[j];
			 } 
			L->r[j+1]=L->r[0];/*插入到正确位置*/
			 
		}
	}
 } 

该算法的特点是:边比较边移动,直到找到正确的位置插入;设置哨兵与有序序列中的元素进行比较,从后往前找到正确的位置,然后进行插入。

时间复杂度:

最好时间复杂度:排序完全是从小到大,不需要进行元素的移动,只需要进行n-1次的比较,时间复杂度为O(n).

最坏时间复杂度:排序完全倒序,总的比较次数和移动次数都最大,时间复杂度为O(n的平方)

平均情况下的时间复杂度为O(n的平方)

空间复杂度:

仅使用了常数个辅助单元,因此空间复杂度为O(1)。

二、折半插入排序:对于数据量不大的排序表,折半插入排序能表现出很好的性能。

折半插入排序与直接插入排序:

1、直接插入排序是边比较边移动;而折半插入排序是先通过折半减少元素比较次数的方式,找到待插入元素的位置,再进行插入。

2、直接插入排序适用于链式和顺序存储的线性表,但是折半插入排序仅仅适合顺序存储的线性表

2、他俩都是一种稳定的排序算法。

 
	L->r[0]=L->r[i];//"哨兵"作用
	low=1;high=i-1;/*设置折半查找的范围,有序序列,0不记,是哨兵*/ 
	while(low<=high)
	{
			mid=(low+high)/2;/*折半*/ 
			if(L->r[mid]>L->r[0]) 
			{
				high=mid-1;/*则查找左半子表 */
			}
			else
			{
				low=mid+1;/*则查找右半子表*/ 
			}
			
			
   } 
		for(j=i-1;j>=high+1;--j)
		{
			L->r[j+1]=L->r[j];/*统一后移操作*/ 
		 } 
		L->r[high+1]=L->r[0];/*插入操作*/ 
	
}

时间复杂度:折半插入排序通过折半减少元素比较次数,时间复杂度约为:O(nlogn),该比较次数与待排序表的初始状态无关,仅取决于表中元素的个数n,移动次数并未改变,它依赖于待排序表的初始状态,因此折半插入排序的时间复杂度为O(n的平方)。

三、希尔排序(缩小增量排序):插入排序适合那种基本有序的排序表和数据量不大的,因此,希尔排序出现。

基本思想:将带排序表分割为若干个形如L[i,i+d,i+2d....]的”特殊"子表,把相隔某个增量的元素构成一个子表,对每个子表使用直接插入排序,当整个表中的元素呈现“基本有序”时,再对全体记录进行一次直接插入排序。可结合下图理解:

void shell(SqList *L)
{
	int i,j,dk;
	for(dk=L->length/2;dk>=1;dk=dk/2) /*增量变化*/ 
	{
		for(i=dk+1;i<=L->length;i++) 
		{
			if(L->r[i]<L->r[i-dk])
			{
				L->r[0]=L->r[i];
				for(j=i-dk;j>0&&L->r[0]<L->r[j];j-=dk)
				{
					L->r[j+dk]=L->r[j];
					
				}
				L->r[j+dk]=L->r[0];
			}
		}
	}
 } 

希尔排序仅适用于顺序存储的线性表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值