【排序】排序算法之插入排序

本文详细介绍了插入排序中的两种方法:直接插入排序和希尔排序。通过对比分析这两种方法的时间和空间复杂度,帮助读者深入理解这两种排序算法的特点及适用场景。

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

排序算法之插入排序

罗朝辉(http://www.cppblog.com/kesalin

转载请注明出处


排序是数据处理中经常使用的一种重要运算,在计算机及其应用系统中,花费在排序上的时间在系统运行时间中占有很大比重,其重要性无需多言。下文将介绍常用的如下排序方法,对它们进行简单的分析和比较,并提供C/C++语言实现。

所谓排序,就是要将一堆记录,使之按关键字递增(或递减)次序排列起来。根据排序所采用的策略,可以分为如上五种:

1、插入排序(直接插入排序、希尔排序);
2、交换排序(冒泡排序、快速排序);
3、选择排序(直接选择排序、堆排序);
4、归并排序;
5、桶排序(桶排序,基数排序);

其中插入排序、交换排序、选择排序、选择排序、归并排序都是基于关键字比较的排序,比较排序的平均时间复杂度好不过 O(nlogn)。

而桶排序是基于映射的排序,其平均时间复杂度可达到 O(n),但桶排序需要额外的空间来存储经过映射的记录。

通常在待排序记录较多的时候,基于映射的排序O(n)比基于比较的排序 O(nlogn) 的效率要高得多,这很好理解:用空间换时间。(查找算法其实也是如此,散列查找比其他查找算法的效率要高得多)。

另外,在讨论一个排序算法的效率时,光看时间复杂度是不够的,还要看待排序记录的规模。比如说,平均时间复杂度为 O(n ^ 2) 的插入排序,冒泡排序等在待排序记录规模较小的情况下,其效率反而比平均时间复杂度为O(nlogn) 的堆排序要好。

废话少说,下面开始简单介绍排序算法及其C/C++语言实现。

插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止。

下面介绍两种插入排序方法:直接插入排序和希尔排序。

直接插入排序


基本思想:将待排序记录分成两部分:有序部分和无序部分,逐个从无序部分中取出记录插入有序部分中的合适位置,使有序部分依然保持有序,直到无序部分为空,完成排序。

代码实现:

1voidinsert_sort(int*array,intlength)
2{
3assert(array&&length>=0);
4
5if(length<=1){
6return;
7}

8
9inti,j,temp;
10for(i=1;i<length;++i){
11temp=array[i];
12j=i-1;
13
14while(j>=0&&temp<array[j]){
15array[j+1]=array[j];
16--j;
17}

18
19array[j+1]=temp;
20}

21}

时间复杂度分析:

直接插入排序算法主要进行有两个操作:查找比较,移动记录,这两个操作均和记录长度 n 相关。其平均时间复杂度为 O(n ^ 2)。这在排序算法里面算慢的,但是当记录较少时,它的效率还是可以不错的。

空间复杂度分析:

直接插入排序只需要一个元素的辅助空间,用于元素的位置交换 O(1)。

补充:

直接插入排序是稳定排序。

它在元素基本有序的情况下(接近最好情况),比较和移动的次数都较少,效率是很高的。

希尔排序(Shell sort)

希尔排序是插入排序的一种,它是利用直接插入排序实现的。

基本思想:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小,通常为 1)时,再对全体元素进行一次直接插入排序。

代码实现:

1voidshell_sort(int*array,intlength)
2{
3assert(array&&length>=0);
4
5if(length<=1){
6return;
7}

8
9inti,j,temp;
10intincrement=length;
11
12do{
13increment=increment/3+1;
14
15//希尔排序中的一趟排序,increment为当前增量
16//将[increment,length-1]之间的记录分别插入各组当前的有序区
17for(i=increment;i<length;++i){
18temp=array[i];
19j=i-increment;
20
21while(j>=0&&temp<array[j]){
22array[j+increment]=array[j];
23j-=increment;
24}

25
26array[j+increment]=temp;
27}

28}
while(increment>1);
29}

时间复杂度分析:

希尔排序的执行时间依赖于增量序列。如果选取好的增量序列呢,总的来说有如下两点:
  ① 最后一个增量必须为 1;
  ② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况,所以一般都取奇数。

希尔排序的平均时间复杂度也为 O(n ^ 2),其效率通常比直接插入排序要高,因为当增量减少到接近 1 时,序列已经基本有序了,前面分析过,直接插入排序在序列基本有序的情况下,效率是很高的。

空间复杂度分析:

直接插入排序只需要一个元素的辅助空间,用于元素的位置交换 O(1)。

补充:

希尔排序是不稳定的。

=============================================

测试代码:

1typedefvoid(*Sort_Function)(int*array,intlength);
2
3structSortFucntionInfo{
4char*name;
5Sort_Functionfunc;
6}
;
7
8SortFucntionInfosort_function_list[]={
9{"直接插入排序",insert_sort},
10{"希尔排序",shell_sort},
11{"",NULL}
12}
;
13
14voidprint_array(constint*a,intlength,constchar*prefix)
15{
16assert(a&&length>=0);
17
18if(prefix){
19printf("%s",prefix);
20}

21
22for(inti=0;i<length;i++){
23printf("%d",a[i]);
24}

25
26printf("/n");
27}

28
29voidtest_sort(Sort_Functionfunc)
30{
31constintlength=11;
32constintcount=2;
33intarray[count][length]={
34{65,32,49,10,8,72,27,42,18,58,91},
35{10,9,8,7,6,5,4,3,2,1,0},
36}
;
37
38for(inti=0;i<count;i++){
39print_array(array[i],length,"original:");
40
41func(array[i],length);
42
43print_array(array[i],length,"sorted:");
44
45printf("/n");
46}

47}

48
49intmain(intargc,constchar*argv[])
50{
51for(inti=0;sort_function_list[i].func!=NULL;i++){
52printf("/n===%s===/n",sort_function_list[i].name);
53test_sort(sort_function_list[i].func);
54}

55
56system("pause");
57return0;
58}


运行结果:

=== 直接插入排序 ===
original: 65 32 49 10 8 72 27 42 18 58 91
sorted: 8 10 18 27 32 42 49 58 65 72 91

original: 10 9 8 7 6 5 4 3 2 1 0
sorted: 0 1 2 3 4 5 6 7 8 9 10


=== 希尔排序 ===
original: 65 32 49 10 8 72 27 42 18 58 91
sorted: 8 10 18 27 32 42 49 58 65 72 91

original: 10 9 8 7 6 5 4 3 2 1 0
sorted: 0 1 2 3 4 5 6 7 8 9 10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值