**
插入排序算法
**
有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据。
1.直接插入排序
直接插入排序的排序思路是:每次将一个待排序的元素与已排序的元素进行逐一比较,直到找到合适的位置按大小插入。
当然,稍微一想,在排序过程中相同元素的位置在排序前后并未发生变化,所以说插入排序是稳定的排序算法。
算法的核心就是比较和移动。
Description
设计一个程序,实现直接插入排序算法,并输出{9,8,7,6,5,4,3,2,1,0}的排序过程。
Input
Output
每个排序过程输出一行,直到排序完成。
Sample Output
9 8 7 6 5 4 3 2 1 0
8 9 7 6 5 4 3 2 1 0
...
...
#include<stdio.h>
int main()
{int a[10]= {
9,8,7,6,5,4,3,2,1,0};int i,j,k,tmp;for(i=1; i<10; i++){tmp=a[i];/*假设手里已有一张牌a[0],摸下一张牌*///printf("a[%d]=%d,tmp=%d\n",i,a[i],tmp);for(j=i; j>0 && a[j-1]>tmp; j--)a[j]=a[j-1];/*移出空位*/a[j]=tmp;/*新牌落位*/for(k=0; k<9; k++)printf("%d ",a[k]);printf("%d\n",a[9]);}return 0;
}
函数封装后
#include<stdio.h>
void Insertion_Sort(int a[],int n)
{int i,j,k,tmp;for(i=1; i<10; i++){tmp=a[i];/*手里已有一张牌a[0],摸下一张牌*///printf("a[%d]=%d,tmp=%d\n",i,a[i],tmp);for(j=i; j>0 && a[j-1]>tmp; j--)a[j]=a[j-1];/*移出空位*/a[j]=tmp;/*新牌落位*/for(k=0; k<9; k++)printf("%d ",a[k]);printf("%d\n",a[9]);}
}
int main()
{int a[10]= {
9,8,7,6,5,4,3,2,1,0};Insertion_Sort(a,10);return 0;
}
2.希尔排序
希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。
希尔排序算法的时间复杂度和步长的选取有关,平均时间复杂度为O(nlog2n),最坏为O(n2),最好为O(n).
直接插入排序更适合于原始记录基本有序的集合。这是因为如果记录基本有序,那么直接插入排序时移动的次数就会很少。而希尔排序正式利用了直接排序的这一个特点,希尔排序将数据按一定的步长进行分组,是的记录很快就会达到整体基本有序。
首先选择一个步长,前面说过不同的初始步长会导致不同的时间复杂度,书上说,希尔排序的步长选择是一个数学难题,所以我们不要纠结。最常用的初始步长就是length/2。在这个例子中,length=9,所以初始步长step=4。然后我们将原序列分成四组(记住,步长是多少就分成多少组!!!!),分组的原则是,同一组中的元素中,每两个元素之间的下标的差为步长step。
然后,分别对每一组按照直接插入排序的方法进行排序(注意,此时每组中相邻的两个元素之间的下标差是步长step,而不是1)结果为:
然后改变步长:step=step/2,所以这一轮的步长为2,然后将数组分成两组(再次说明,步长是多少,就分多少组)。如下(相同颜色为一组):
然后按照直接插入进行排序 然后,继续改变步长,step=step/2,所以这一轮的步长为1,此时素组就分成一组了:
然后,按照直接插入排序进行排序, 接下来改变步长,step=step/2,步长为0,结束。
通过上面的例子我们可以看到,实际上对分成的每一个组,进行的操作还是直接插入排序,只不过处理时,要考虑相邻两个元素之间的下标差不在是1,而是step。所以,我们首先要对上面直接插入排序的函数insert_sort()进行必要的修改,加入两个参数:首元素的下标(以确定是对哪一组数据进行直接排序)和步长。如下:
最后主函数中,主要任务就是分组,然后对每组数据都调用insert_sort()函数,还是再次强调:step是多少就分多少组!!!