排序算法--插入排序

排序思想

将待排序数组分为有序表和无序表,每次从无序表中取出一个元素,插入到有序表的合适的位置。一开始有序表是一个数arr[0],无序表是n-1个数(arr[1],arr[n-1])。

每遍历一次,有序表的元素个数增加一个,无序表中元素个数减少一个,重复n-1次,完成排序。

过程分析

假设我们排序前:有一个数组arr,大小为6。存储的数据依次为20、30、40、10、60、50。

 第1次开始判断时,我们都是假定a[0]为有序区,后面都是无序区。所以,目前有序的只有20。

第1次进行插入的时候,取a[1], 与有序区的所有元素进行比较,比较进行到a[1]>a[x]这个条件满足为止。在本题中,30、40这两次插入都是插入到初始位置,插入过程不明显。下面直接看第三次插入过程:

插入前,将第3次的数据进行存储int tmp=arr[3],然后tmp与arr[2]进行比较,tmp<arr[2],条件不满足,令arr[3]=arr[2],arr[2]位置留空。tmp与arr[1]进行比较,tmp<arr[1],条件不满足,令arr[2]=arr[1],arr[1]位置留空。tmp与arr[0]进行比较,tmp<arr[0],条件不满足,令arr[1]=arr[0],arr[0]位置留空。有序区全部比较完成,空位为0,所以将tmp放入arr[0],即arr[0]=tmp。

然后按同样的方法插入60和50这两个元素。

 代码实现

C语言版:

//插入排序:时间复杂度 O(n^2),稳定
void InsertSrot(int* arr, int size)
{
	for (int i = 1; i < size; i++) {
		int tmp = arr[i];
		int j = 0;
		for (j = i; j > 0; j--) {
			if (tmp < arr[j - 1])
				arr[j] = arr[j - 1];//(j-1)->(j),值右移
			else break;//如果在有序部分没有比"这个数"小,不可能比"这个数"前面小了,结束小循环吧。此时j指向"这个数"的后面一个位置
		}
		arr[j] = tmp;//将这个位置被本次大循环的a[i]原本的值取代。实现了插入的操作。
	}
}

C++版:

void insertSort(vector<int>& v)
{
    for(int i=1;i<v.size();i++){//表示循环需要的趟数(无序区待排序的元素个数)
        //i同时也表示无序区第一个元素--有序区待插入元素的下标
        int tmp=v[i];//存放无序区的第一个元素,防止前面元素后移时对元素的覆盖
        int j=i;//如果j在for循环内部进行定义,那么后面的空位就找不到了
        for( ;j>0;j--){
            if(tmp<v[j-1])
                v[j]=v[j-1];//如果满足条件就将值右移
            else break;//直到不满足条件,退出循环,j表示元素空位
        }
        v[j]=tmp;
    }
}

算法分析

时间复杂度:O(n²)

最好时间复杂度:排序数组本身有序,每次进入小循环1次就会直接跳出小循环,此时时间复杂度为O(n)。

最坏时间复杂度:排序数组本身为逆序,每次循环都会比较到第一个元素(索引0位)。从无序区第1个元素进行比较需要进行比较1次,第2个元素需要进行2次比较....第n-1个元素需要n-1次比较。所以最坏需要进行的比较次数为1+2+3+...+(n-1),等差数列和的最高阶为n²,所以最坏时间复杂度为O(n²)。

平均时间复杂度:O((n+n²)/2)=O(n²)。

稳定性:排序时我们会按照从前往后的顺序依次插入有序区,假如我们元素依次为9876631,在排序时第一个6会放在合适的位置,然后对第二个6进行插入时,直到后者6与前者6进行比较时,6<6不满足,跳出小循环,后者6就放在了前者6的后面一个位置。相同元素的相对前后位置没有发生改变,所以该排序算法是稳定的。


推荐观看: 

1.0 十大经典排序算法 | 菜鸟教程 (runoob.com)

最详细的排序算法讲解!一看就懂! - 知乎 (zhihu.com)

几种常见的排序方法 - 一y样 - 博客园 (cnblogs.com)

十大经典排序算法【算法思想+图解+代码】【数据结构与算法笔记】_经典算法题图解快速排序-CSDN博客


感谢大家!

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值