【排序算法】直接插入排序与希尔(Shell)排序

直接插入排序 是依次将每个元素插入到一个有序的序列当中去,可以用抓扑克牌来类比,实现如下:

/*插入排序*/
void insert_sort(int Array[],int Len)
{
	//可以用抓扑克牌类似
  int temp=0,j=0;
 for(int i=1;i<Len;i++)
 {      temp=Array[i];
        j=i-1;
		while(j>=0&&temp<=Array[j])
        {
             Array[j+1]=Array[j];
			 j--;
        }
        Array[j+1]=temp;
 }
}
插入排序算法是稳定的,最坏情况时间复杂度为:O(n^2),最好为:O(n),平均情况:O(n^2)
希尔排序:希尔排序(Shell Sort)又称为缩小增量排序,输入插入排序算法,是对直接排序算法的一种改进。

 希尔排序是基于插入排序的以下两点性质而提出改进方法的:

    1)插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率

    2)但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

2、算法思想 

    希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

    假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n^2)的排序(冒泡排序或插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。

    一个更好理解的希尔排序实现:将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身仅仅对原数组进行排序(通过增加索引的步长,例如是用i += step_size而不是i++)。

    数学表述为先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

    该方法实质上是一种分组插入方法。

    例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:

    13 14 94 33 82

    25 59 94 65 23

    45 27 73 25 39

    10

    然后我们对每列进行排序:

    10 14 73 25 23

    13 27 94 33 39

    25 59 94 65 82

    45

    当我们以单行来读取数据时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,然后再以3为步长进行排序:

    10 14 73

    25 23 13

    27 94 33

    39 25 59

    94 65 82

    45

    排序之后变为:

    10 14 13

    25 23 33

    27 25 59

    39 65 73

    45 94 82

    94

    最后以1步长进行排序(此时就是简单的插入排序了)。

3、算法实现

void ShellSort(int Array[],int n)
{
	int i,j,gap;
	int temp;
	gap=n/2; //增量初始值
	while(gap>=1)
	{
		for(i=gap;i<n;i++)//对所有相隔gap位置的所有元素进行插入排序
		{
			temp=Array[i];
			j=i-gap;
			while(j>=0&&temp<Array[j]) //对相隔gap位置的元素组进行排序
			{
				Array[j+gap]=Array[j];
				j=j-gap;
			}
			 Array[j+gap]=temp;
             j=j-gap;
		}
		 Display(Array,n);
		gap=gap/2;  //减少增量
	
	}
	
}
//输出数组
void Display(int array[],int length)


{
         for(int i =0;i<length;i++)


         {
                   cout<<array[i]<<", ";
         }


         cout<<endl;
}

主函数:

void main(int argc,char *argv[])
{
	
	int Array[]={5,4,8,9,3,2,10,6};
	int Len=sizeof(Array)/sizeof(int);
	ShellSort(Array,Len);
	 printf("排序好的数组为:");
	  Display(Array,Len);}



4、算法分析

     希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。

     最差时间复杂度   根据步长序列的不同而不同。 最坏的情况下复杂度为: O(nlog^2n)

     

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


    由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值