算法排序(2):插入排序

插入排序有直接插入排序和希尔排序俩种,我们分别来看:

一、直接插入排序

直接插入排序的原理是将数据分为已排序和待排序俩部分,每次从待排序部分获取一个数据,从已排序的部分找到适合位置插入,直到待排序的数据全部取完。

稳定性:稳定
时间复杂度:最好O(N),平均O(N2), 最坏O(N2)
空间复杂度:O(1)

举个栗子:
需要排序的数据为:4 8 3 6 1
1.先将4作为已经排序部分,8 3 6 1 为待排序部分
2.从待排序部分取出8,插入到已经排序的部分中
3.插入后已排序结果为4 8,整体为 4 8 3 6 1(黑体为已经排好的部分)
4.继续以上操作,取出3插入3 4 8 6 1
5.取出6插入3 4 6 8 1
6.取出1插入1 3 4 6 8
待排序取完数据后,可以得到结果,数据已经全部排好序了。
在插入数据时,为了插入到合适的位置,可能要移动已排好的数据,从而时间复杂度会比较高,也就是说,直接插入排序适合数据量较少,而且比较有序的数据排序。

接下来用代码实现:

void insertsort(int arr[],int len)
{
    int tmp=0;
    int j=0;
    for(int i=1;i<len;i++)
    {
        tmp=arr[i];
        j=i-1;
        while(j>=0&&arr[j]>tmp)
        {
            arr[j+1]=arr[j];
            j--;
        }
        arr[j+1]=tmp;
    }
}

二、希尔排序

希尔排序是直接插入排序的升级,用来弥补直接插入排序适合数据量少的缺点。
算法思想是确定一个增量组合,通过增量来划分大数据,每一次划分好数据,对划分的数据分别进行直接插入排序(数据较为无序,但是数据量大大减少),直到最后的增量为一(此时数据已经较为有序),进行最后一次直接插入排序。

稳定性:稳定
时间复杂度:最好O(N),平均O(N1.3), 最坏O(N2)
空间复杂度:O(1)

接下来用代码实现:

void shell(int arr[],int arr_len,int dk)   //一次SHELL
{
    int tmp,j;
    for(int i=dk;i<arr_len;i++)
    {
        tmp=arr[i];
        j=i-dk;
        while(j>=0&&arr[j]>tmp)
        {
            arr[j+dk]=arr[j];
            j-=dk;
        }
        arr[j+dk]=tmp;
    }
}

void shellsort(int arr[],int arr_len,int dka[],int dka_len)    //希尔排序总控制
{
    for(int i=0;i<dka_len ;i++)
    {
        shell(arr,arr_len,dka[i]);
    }
}

由于希尔排序不稳定,我们来做一点修改,让它变得稳定。我的一个简单思路是,首先将待排序数组预处理,将重复的数据筛选出来,直到无重复数据部分进行最后一次希尔排序,重复数据参与这最后一次希尔排序,即转化为一次直接插入排序,我们知道直接插入排序是稳定的,所以本次希尔排序也稳定。

代码如下:

int init(int arr[],int arr_len,int *brr,int *crr)
{
    int i=1;
    int j=1;
    int k=0;
    int key=0;
    brr[0]=arr[0];
    for(i;i<arr_len ;i++)
    {
        key=k;
        for(int p=0;p<j;p++)
        {
            if(brr[p]==arr[i])
            {
                crr[k]=arr[i];
                k++;
                break;
            }
        }
        if(key==k)
        {
            brr[j]=arr[i];
            j++;
        }
    }
    return k;
}

void shell(int arr[],int arr_len,int dk)
{
    int tmp,j;
    for(int i=dk;i<arr_len;i++)
    {
        tmp=arr[i];
        j=i-dk;
        while(j>=0&&arr[j]>tmp)
        {
            arr[j+dk]=arr[j];
            j-=dk;
        }
        arr[j+dk]=tmp;
    }
}

void show(int arr[],int len)
{
    for(int i=0;i<len;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
}

void shellsort(int arr[],int arr_len,int dka[],int dka_len,int *brr,int *crr)
{
    int crrlen=init(arr,arr_len,brr,crr);
    for(int i=0;i<dka_len-1 ;i++)
    {
        shell(brr,arr_len-crrlen,dka[i]);
    }
    int j=0;
    for(j;j<arr_len-crrlen;j++)
    {
        arr[j]=brr[j];
    }
    for(int k=0;k<crrlen;k++)
    {
        arr[j]=crr[k];
        j++;
    }
    show(arr,arr_len);
    shell(arr,arr_len,1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值