1、什么是插入排序
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
从第二个元素开始r[1],那么将他左边的元素作为一个已经有序的序列,将r[1]按从小到大的顺序插入到
有序序列中的合适位置使之成为一个新的有序序列;接着将r[2]插入到左边的有序序列中,使之成为一个
新的有序序列,依次类推,直道将所有的元素都遍历完了之后,那么整个数组就是一个从小到大的有序数组了。
2、效果演示
这是需要进行排序的序列
对于第1个元素8来说,它本身就是有序的
再来考虑第2个元素6,因为他比8小,交换一次位置
再来考虑第3个元素2,因为他比8小,交换一次位置
2又比左边的6小,交换一次位置
再来考虑第4个元素,因为他比8小,交换一次位置
3又比左边的6小,交换一次位置
3比左边的2大,不需交换,前4个元素就已经排序完毕,后面的依次类推
2、时间复杂度
O(n^2)
3、算法实现(基于C++)
1 /* 直接插入排序算法实现 */ 2 template<typename T> 3 void insertSort(T a[], int count) 4 { 5 /* 找到a[i]这个元素的合适插入位置,因为第一个元素前面没有元素,无法进行比较,所以从第二个元素开始 */ 6 for (int i = 1; i < count; i++) { 7 for (int j = i; j > 0 && a[j - 1] > a[j]; j--) { 8 std::swap(a[j-1], a[j]); 9 } 10 } 11 }
4、直接插入算法的改进
从上面的算法实现上可知,我们的直接插入排序算法上需要进行大量的两个元素交换的动作(swap函数),而两个元素交换在实现上是需要进行3次的赋值操作,所以会给整个过程造成大量的时间浪费,所以我们将对上面在算法的实现上进行一个改进,通过改进之后可以大大的缩短直接插入排序算法的所需要的时间。
改进的思想: 其实就是通过直接的赋值操作代替大量的数组元素间的互换操作,具体的实现请看下面的演示
首先还是从第2个元素开始排序,这次我们先将6这个元素拷贝出来一份,然
后再与左边的8进行比较,6副本比8小,将8往右移动,再将6副本指针往左移动
直接将6副本赋值给当前所指向的这个位置,此时前面2个元素排序完毕
考虑第3个元素,还是先将其复制一份,2副本比左边的8小,将8往右移动,
将2副本指针往左移动
2副本又比左边的6小,将6往右边移动一次,将2副本指针往左移动
直接将2副本赋值给当前所指向的这个位置
前面3个元素排序完毕
再来考虑第4个元素,首先还是先将其拷贝一份,3副本比左边的8小,直接
将8往右移动,将3副本指针往左移动
3副本又比左边的6小,将6往由移动,3副本指针往左移动
此时3副本比左边的2大,这个位置合适,将3副本赋值给当前所指向的这个位置
至此前面的4个元素排序完毕,依次类推
由此可以知道经过上面的方法之后,减少了两个元素之间的交换操作,大大缩短了时间。
算法的实现如下:
1 /*********************************** 直接插入排序算法实现 ********************************/ 2 template<typename T> 3 void insertSort (T a[], int count) 4 { 5 /* 找到a[i]这个元素的合适插入位置,因为第一个元素前面没有元素,无法进行比较,所以从第二个元素开始 */ 6 for (int i = 1; i < count; i++) { 7 int j; 8 T copy = a[i]; // 将需要插入到左边有序序列的元素拷贝出来作为一个副本 9 for (j = i; j > 0 && a[j - 1] > copy; j--) { 10 a[j] = a[j - 1]; // 如果条件满足,直接前一个元素赋值给后面的元素 11 } 12 a[j] = copy; // 找到该元素的合适位置之后直接赋值即可 13 } 14 } 15 /**********************************************************************************************/
我们将一系列的元素之间的交换变成了赋值操作,大大的缩短了排序所需要的时间,可以大大提高程序运行的效率。
5、总结
(1)插入排序的时间复杂度是O(n^2)级别
(2)插入排序的内层循环是可以提前终止的,因为只要找到了合适的位置,将元素插入到该位置后就可以终止本次循环了。
(3)如果需要进行排序的数组序列本来就是一个非常有序的状态,那么插入排序执行起来的效果将比选择排序快上很多,因为插入排序的内层循环将大大的减少时间,而选择排序内层循环每一次都会循环到底,所以在时间上将远远超过插入排序,所以当需要排序的数组序列本来就是一个非常有序的状态,那么内层的循环基本上不用做了,这样会大大提升效率。当需要进行排序的序列几乎接近于有序时,插入排序的时间复杂度将会变为n级别。