插入排序--直接插入、折半插入、希尔排序

插入排序,顾名思义,就是将一个待排序的记录按照关键字的大小,插入到前面已排序好的子序列中,直到全部的记录都插入完成为止。三个重要的插入排序算法:直接插入排序、折半插入排序、希尔排序。

1.直接插入排序

(假定为从小到大排序)

基本思路:定义一个中间元素tep,从一个无序序列的第二个元素开始(此时这个元素的前面为有序序列,后面为无序序列),将其与第一个元素比较,若a[1]<a[0],则将a[1]的值赋给中间元素tep,而后将从a[0]开始的元素全部后移一位(无须担心a[1]的值被覆盖,因为早已将其转移到tep中),再将tep赋给a[0];若a[1]>a[0],则无序序列后移一位,最后重复步骤。

说白了,就是a[i]前的序列为有序的,a[i]后的序列为无序的,用a[i]和有序序列一一比较,a[i]小则插入,大则后移,a[i]并入到有序中,进行a[i+1]的比较。

typedef int Elemtype;
void InsertSort(Elemtype a[],int n)
{
    int j=0,tep=0;
    for(int i=1;i<n;i++)//从第二个元素开始插入
    {
        if(a[i]<a[i-1])
        {
            tep=a[i];
            for(j=i-1;tep<a[j];j--)//从有序表的后往前依次比较,便于交换后移,从前面开始太过复杂
                a[j+1]=a[j];//将有序表后移
            a[j+1]=tep;//此时j已经往前移了一位,所以要+1 
        }
    }
}

空间效率:空间复杂度为O(1)。

时间效率:最好最坏情况平均下,时间复杂度为O(n^2)。

适用性:顺序存储和链式存储的线性表。

2.折半插入排序

(假定为从小到大排)

基本思路:在有序序列中使用二分查找查找插入位置,其他步骤同直接插入排序一样。

typedef int Elemtype;
void BinarySort(Elemtype a[],int n)
{
    for(int i=1;i<n;i++)
    {
        int tep=a[i];
        int left=0,right=i-1;//在已排序序列中用二分查找要插入的位置
        while(left<=right)
        {
            int mid=(left+right)/2;
            if(tep<a[mid])
                right=mid-1;
            else//tep=a[mid]时无须替换,left后移就行了
                left=mid+1;
        }
        for(int j=i-1;j>=left;j--)//后移一位,注意是j>=left
            a[j+1]=a[j];
        a[left]=tep;//为什么是left?因为此时的left是mid的后面一个,也就是刚好需要替换的一个
    }
}

空间效率:空间复杂度为O(1)。

时间效率:最好最坏情况平均下,时间复杂度为O(n^2)。

3.希尔排序

基本思路:先将数组按照一定间隔(称为增量)分成若干个子序列,对每个子序列进行插入排序,然后逐次减小增量,重复上述过程,直到增量为1时执行最后一次插入排序,使得整个序列有序。

希尔排序的关键在于选择合适的增量序列。常见的增量序列有希尔增量(N/2)、Sedgewick增量等。一般情况下,希尔增量被认为是较优的选择。

希尔排序的实现过程:

  1. 初始化增量gap,设数组长度为n;

  1. 如果gap大于等于1,则继续执行步骤3,否则退出排序;

  1. 将数组分为gap个子序列,对每个子序列进行插入排序;

  1. 减小增量gap,重复步骤2。

void shellSort(int arr[],int n) 
{
    // 选择一个递减的增量序列
    for(int gap=n/2;gap>0;gap/=2) 
    {   
        // 对每个子数组进行插入排序
        for(int i=gap;i<n;i++) //此语句表示一共有n-gap个子序列
        {
            int tep=arr[i];
            int j=i-gap;
            while(j>=0 && arr[j]>tep) 
            {
                arr[j+gap]=arr[j]; //将大的数换到后面去
                j-=gap;//一组一组排序
            }
            arr[j+gap]=tep;//没执行while时相当于没操作;执行了while时,此时的j是负数,加上gap就是将tep赋给前者。
        }
    }
}

举个栗子:

空间效率:空间复杂度为O(1)。

时间效率:n在某特定范围内的时间复杂度约为O(n^1.3);最坏情况下,时间复杂度为O(n^2)。

适用性:仅适用于线性表为顺序存储的情况。

猜你喜欢

转载自blog.csdn.net/weixin_58420524/article/details/129326781
今日推荐