插入排序算法(直接插入/折半插入/希尔排序)

  • 内排序:指在排序期间数据对象全部存放在内存的排序;
  • 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。
  • 排序算法的分析

    <1>排序算法的稳定性

    如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j]。如果排序前后,对象r[i]和r[j]的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

    <2>排序算法的评价

    时间开销

  • 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
  • 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算

      空间开销

  • 算法执行时所需的附加存储。

插入排序基本思想

每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。

分类(根据寻找插入位置方法分为)

  • 直接插入排序
  • 折半(二分)插入排序
  • 希尔插入排序

<1>直接插入排序

基本思想:在含有i个记录的有序子序列r[0.....i-1]中插入一个记录r[i]后,变成含有i个记录的有序子序列r[0...i],和顺序查找类似。在自i-1起往前搜索的过程中,可以同时后移记录。整个排序过程为进行n-1趟插入,即:先将序列中的第一个元素看作有序的子序列,然后从第二个记录起逐个进行插入,直至整个序列变成按关键字非递减有序序列为止。

代码体现:

void InsertSort(int arr[],int len)
{
	int i,j;
	for(int x=0;x<len;x++)
		cout<<arr[x]<<" ";  //输出原始数据
	cout<<endl;
	for(i=1;i<len;i++)
	{
		if(arr[i]<arr[i-1])
		{
			int k=arr[i];
			arr[i]=arr[i-1];
			for(j=i-2;k<arr[j]&&j>=0;j--)
			{
				arr[j+1]=arr[j];    //将比待插入值大的数据后移
			}
			arr[j+1]=k;   //将所要插入的数据插入到确定的位置
		}
		for(int m=0;m<len;m++)
			cout<<arr[m]<<" ";
		cout<<endl;
	}
}

我们这个代码的效率可是比下面这个代码效率高呦,本人亲测(认真脸) 

void Insert_sort(int arr[],int len)
{  
	for(int i=1;i<len;i++)
	{
		for(int j=i;j>0&&arr[j]<arr[j-1];j--)
		{
			int k=arr[j];
			arr[j]=arr[j-1];   //交换元素
			arr[j-1]=k;       //将比当前元素大的元素往后移动
		}
	}
}

第二个代码就是它的交换次数显然高于第一个 代码,所以显然要比它慢一些啦。

复杂度分析:

1:空间复杂度:只需要一个记录的辅助空间

2:时间复杂度:

  • 最好情况下,排序前对象已经按照要求的有序。比较次数为n-1次; 移动次数为0次。则对应的时间复杂度为O(n)。
  • 最坏情况下,排序前对象为要求的顺序的反序。第i趟时第i个对象必须与前面i个对象都做排序码比较,并且每做1次比较就要做1次数据移动(具体可以从下面给出的代码中看出)。比较次数为约等于n²/2;

       移动次数为约等于n²/2。则对应的时间复杂度为O(n²)。

  • 如果排序记录是随机的,那么根据概率相同的原则,在平均情况下的排序码比较次数和对象移动次数约为n²/4,因此,直接插入排序的时间复杂度为O(n²)

3:算法稳定性:直接插入排序算法是稳定的,不改变相同元素原来的位置。

<2>折半插入排序

1:基本思想:由于插入排序的基本操作是在一个有序表中进行查找和插入,那么这个查找用折半查找来实现即为折半插入排序

2:代码体现:

void BInsertSort(int arr[],int len)//在直接插入排序的基础上改进,处理更多的数量
{  
	for(int i=1;i<len;i++)
	{
		int k=arr[i];
		int low=0;
		int high=i-1;
		while(low<=high)    //二分查找,提高了查找效率,找到插入的位置
		{
			int m=(low+high)/2;
			if(k<arr[m])
			{
				high=m-1;
			}
			else
			{
				low=m+1;
			}
		}
		for(int j=i;j>high+1&&j>0;j--)
		{
			arr[j]=arr[j-1];   //移动的时间其实并没有改变
		}
		arr[high+1]=k;
	}
}

3:复杂度分析

  • 空间复杂度:从算法容易看出在空间复杂度上与直接插入排序一致,只需要一个记录的辅助空间
  • 时间复杂度:折半插入排序仅减少了关键字之间的比较次数,而记录的移动次数不变,因此时间复杂度仍为O(n²)
  • 稳定性:稳定的排序

<3>希尔排序

猜你喜欢

转载自blog.csdn.net/Eunice_fan1207/article/details/82468085
今日推荐