经典算法之三:插入排序及二分优化

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

 

设数组为a[0…n-1]。

1.      初始时,a[0]自成1个有序区,无序区为a[1..n-1]。令i=1

2.      将a[i]并入当前的有序区a[0…i-1]中形成a[0…i]的有序区间。

3.      i++并重复第二步直到i==n-1。排序完成。

直接插入排序

基本思想

当插入第 i(i1) 个对象时,前面的 V[0],V[1],,V[i1] 已经排好序。这时,用 V[i] 的排序码与 V[i1],V[i2],,V[0] 的排序码顺序进行比较,找到插入位置即将 V[i] 插入,原来位置上的对象向后顺移。

直接插入排序图示

这里写图片描述

从上到下,分别展示了直接排序算法的所有可能的过程,包括相同排序码的排序方式(保持了原来的顺序,说明是稳定排序)以及in-place操作中的元素移动等。

这里写图片描述

直接插入排序算法分析

设待排序对象个数为 n ,则该算法的主程序执行 n1 排序码比较次数和对象移动次数与对象排序码的初始排列有关

  • 最好情况下,排序前对象已经按照要求的有序。比较次数(KCN): n1  ; 移动次数(RMN):为 0 。则对应的时间复杂度为 O(n)
  • 最坏情况下,排序前对象为要求的顺序的反序。第 i 趟时第 i 个对象必须与前面 i 个对象都做排序码比较,并且每做1次比较就要做1次数据移动(具体可以从下面给出的代码中看出)。比较次数(KCN): n1i=1i=n(n1)2n22  ; 移动次数(RMN):为 n1i=1i=n(n1)2n22 。则对应的时间复杂度为 O(n2)
  • 如果排序记录是随机的,那么根据概率相同的原则,在平均情况下的排序码比较次数和对象移动次数约为 n24 ,因此,直接插入排序的时间复杂度 O(n2)
直接插入排序算法的特点
  • 它是稳定排序,不改变相同元素原来的顺序。
  • 它是in-place排序,只需要 O(1) 的额外内存空间。
  • 它是在线排序,可以边接收数据边排序。
  • 它跟我们牌扑克牌的方式相似。
  • 对小数据集是有效的。

算法分析

直接插入排序的算法性能


时间复杂度
  

当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为O(N)。 

当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为O(N2)

所以,数据越接近正序,直接插入排序的算法性能越好。 

 

空间复杂度

由直接插入排序算法可知,我们在排序过程中,需要一个临时变量存储要插入的值,所以空间复杂度为 1 。

 

算法稳定性

直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是稳定的算法。 

 

完整参考代码

直接插入排

完整代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5;
void Init(int *a,int *b,int n)
{
    srand(time(NULL));
    for(int i=0; i<n; i++)
        b[i]=a[i]=rand()%100;
}
void P(int *a,int n)
{
    for(int i=0; i<n; i++)
        cout<<a[i]<<"  ";
    cout<<endl;
}
void Insert_Sort(int *a,int n)
{
    int i,j;
    for(i=1; i<n; i++)
    {
        if(a[i]<a[i-1])
        {
            int t=a[i];
            for(j=i-1; j>=0&&a[j]>t; j--)
            {
                a[j+1]=a[j];
            }
            a[j+1]=t;
        }
        //P(a,i);
    }
}
//二分优化
void Insert_Sort_Binary(int *a,int n)
{
    for(int i=1; i<n; i++)
    {
        if(a[i]<a[i-1])
        {
            int left=0;
            int right=i-1;
            int t=a[i];
            while(left<=right)
            {
                int mid=(left+right)>>1;
                if(a[mid]>t)
                    right=mid-1;
                else
                    left=mid+1;
            }
            for(int j=i-1; j>=left; j--)
            {
                a[j+1]=a[j];
            }
            a[left]=t;
        }
        //P(a,i);
    }
}
int main()
{
    int a[MAXN],b[MAXN];
    char ch;
    do
    {
        Init(a,b,MAXN);
        //P(a,MAXN);
        time_t t1=clock();
        Insert_Sort(a,MAXN);
        time_t t2=clock();
        cout<<t2-t1<<endl;
        //P(a,MAXN);
        //P(b,MAXN);
        time_t t3=clock();
        Insert_Sort_Binary(b,MAXN);
        time_t t4=clock();
        cout<<t4-t3<<endl;
        //P(b,MAXN);
    }
    while(ch=getchar());

    return 0;
}



参考博客:http://blog.csdn.net/morewindows/article/details/6665714

https://www.cnblogs.com/jingmoxukong/p/4303270.html

http://blog.csdn.net/lg1259156776/article/details/48689323

https://www.cnblogs.com/Braveliu/archive/2013/01/09/2852641.html

https://www.cnblogs.com/huangxincheng/archive/2011/11/20/2255695.html


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值