排序-->插入排序(直接插入排序&&希尔排序)

写在前面

博客的全部代码以及测试用例全部已上传GitHub:直接插入排序&&希尔排序

直接排序

直接排序其实就是一次将无序空间向有序空间转换的过程,其实所有排序都是这样,只不过,在直接排序中,我们是将原本的数据内容分为了前后两个空间,前面的一个空间是有序的,而后面的空间无序,我要做的就是慢慢的将有序空间增长,将无序空间缩小,直到无序空间为0,我们就可以得到一个有序的数据链;这里写图片描述
在上图中,我们大致可以观察出这套算法所运行的过程:

  1. 在原始数组中,默认第一个数字是有序的,其他后面的数字全部无序;
  2. 在无序的数字中,从前向后开始,取第一个数字与有序区域的数字从后向前比较;
  3. 如果有序中的数字大于该数字,就将大于的数字向后移一位;
  4. 直到遇到一个小于或者等于它的数字,就讲该数字插入到当前位置;
  5. 直到全部有序,否则就重复2-4的步骤;
//version1 时间复杂度O(N^2)
void InsertSort(int *array, size_t size)
{
    for (size_t idx = 1; idx < size; ++idx)
    {
        int end = idx - 1;
        int key = array[idx];
        while (end >= 0 && (key < array[end]))
        {
            array[end + 1] = array[end];
            --end;
        }
        array[end + 1] = key;
    }
}

我们可以看到,在上面的代码中,确实比较简单,到那时事件复杂度达到了O(N^2);其实,我们可以在这个代码中找到一些,我们原来学习到的东西,替换它,比如在有序空间中找数字时,可以用到二分查找;

//version2 时间复杂度降低,利用二分查找来找位置
void InsertSort_OP(int *array, size_t size)
{
    for (size_t idx = 1; idx < size; ++idx)
    {
        int end = idx - 1;
        int left = 0;
        int right = idx;
        int key = array[idx];
        while (left <= right)
        {
            int mid = left + ((right - left) >> 1);
            if (key < array[mid])
                right = mid - 1;
            else
                left = mid + 1;
        }
        while (end >= left)
        {
            array[end + 1] = array[end];
            --end;
        }
        array[end + 1] = key;
    }
}

希尔排序

从根本意义上来讲,希尔排序其实就是直接插入排序的一个改良版,希尔排序的速度要远胜于直接插入排序;
这里写图片描述

从图中可以看到:
1. 我们将原始数据分割按照某个个数分割为几个分组;
2. 然后一直按照默认的大小一直分割下去,知道只有一个元素时停止(前面如果按照规定的元素个数来划分有剩余的话就轮空);
3. 然后从下向上一次排序;知道数组全部有序;
4. 其中,我在画图的时候只是随意的切割方法,其实在很多前辈做了大量的测试后发现,当gap = gap/3+1;时是效率最高的;

//希尔排序  时间复杂度在N^1.25~1.6N^1.25
void ShellSort(int *array, size_t size)
{
    int gap = size;
    while (gap > 1)
    {
        gap = gap / 3 + 1;
        for (size_t idx = gap; idx < size; ++idx)
        {
            int end = idx - gap;
            int key = array[idx];
            while (end >= 0 && (key < array[end]))
            {
                array[end + gap] = array[end];
                end -= gap;
            }
            array[end + gap] = key;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值