直接插入排序

介绍

直接插入排序(Straight Insertion Sort)是一种最简单的排序方法,其基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的、记录数量增1的有序表。

用法与要点

先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:

  1. 设立哨兵,作为临时存储和判断数组边界之用。
  2. 如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

代码实例

先看看我自己写的,比较简单易懂一些

public static int[] arr = new int[] { 67, 88, 90, 17, 69, 20, 77, 42, 16, 12, 17 };
public static void InsertSort()
{
    for (int i = 1; i < arr.Length; i++)
    {
        // 碰到临近的上一个下标的数值比当前下标的数值大的,进行调换位置
        if (arr[i-1] > arr[i])
        {
            int j = 0; 
            // 默认是i下标之前的都是排序好的
            for (j = i-1; j >= 0; j--)
            {
                // 如果排序好的序列中的数值比当前下标的数值还要大,就行换位置
                if (arr[j] > arr[i])
                {
                    int temp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp;
                }
                // 换完位置,记得之前排序好的序列需要重新排序
                if(j > 0 && arr[j] < arr[j-1]) 
                {
                    int temp2 = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp2;
                }
            }
        }
    }
}

再看看大佬写的,大家可以对比一下,看看大佬的代码优势在哪里!尽量向大佬学习。

// 遍历array数组
// 为什么要从1开始,因为假设0坐标这部分是已经排序好的,从小到大排序好的,
// 先将序列的第1个记录看成是一个有序的子序列
for (int i = 1; i < array.Length; i++)
{
    // 如果i-1坐标的值,大于i坐标的值
    if (array[i] < array[i-1])
    {
        // 使用temp临时变量存储array[i]的数值   
        int temp = array[i];
        
        // 标记,哨兵
        int j = 0;
        
        // 从i开始递减遍历,因为确定i前面都是从小到大排序好的(有序数组)
        // 当i等于1的时候,j >= 0其实是为了防止数组溢出,因为arry[-1]为空,会报错
        // (temp<array[j])其实就是(array[i]<array[i-1]),因为temp是array[i],而j = i-1,就是array[i-1]
        for (j = i-1; j >= 0 && temp < array[j]; j--)
        {
            // j + 1永远等于i,所以这里其实是把array[i]变成了array[i-1]
            // 因为实际情况是array[i]的值是比array[i-1]的值小
            array[j + 1] = array[j];
        }
        
        // 这时候,遇到了j越界,或者小坐标的值大于后坐标的值
        // 这时候j基本上等于i-1-1,也就是j+1=i-1。
        // 说到最后还是间接的实现了,两个数的交换
        array[j + 1] = temp;
    }
}

看到这里,作者突然理解了。什么是插入排序,插入排序的本质就是直接插入,而上面插入排序的精髓点就是如下代码:

for (j = i-1; j >= 0 && temp < array[j]; j--)
{
    // 将比temp大的数集体往后移动
    array[j + 1] = array[j];
}
// 最后找到比temp小的数,然后往这个数的后面一个下标插入temp数
array[j + 1] = temp;

这两句就是整个排序插入的精髓所在

算法复杂度分析

从两串代码的的算法来看。时间复杂度基本上都是O(n²),为什么,因为两个遍历都是跟数组的长度也就是相当于n有关,空间复杂度都是O(1),因为遍历循环的时候,没必要使用数组来存储。这只是大致上来说的,如果真的要说的严谨一点。那么我们继续分析一下。

假设,一行代码就运行1秒,排除大括号,每个遍历都假设成需要遍历n次,那么我的第一行就会运行1秒,然后后面到第二个for循环之前都是需要运行n次的,迄今为止也就是n+n+1秒,第二个for循环代码又运行n秒,那就是3n+1秒,第二个for循环里面是需要走n*n次的,也就是最坏的情况是8n²,那么最后结果是3n+1+8n²秒。

同理可得,大神的代码最坏是需要4n+n²+1秒的,所以还是大神的代码写的完美,优化的比较彻底。大神的代码来自这里:
点击跳转查看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值