1、什么是插入排序?
先看一个例子:{7,6,1,9,3}无序数列中,我们约定好无序数列的第一个元素7作为有序数列{7},然后分别对{6,1,9,3}的数与7进行比较移位得到新的有序数列。
第一次迭代:{7} 6,1,9,3 拿出第二数6,插入到排好序的{7}中,与排好序的{7}进行比较,得到有序数列{6,7}
第二次迭代:{6,7} 1,9,3拿出第三个数1,插入到排好序的{6,7}中,与排好序的{6,7}数分别进行比较,得到有序{1,6,7}
第三次迭代:{1,6,7} 9,3拿出第四数9,插入到排好序的{1,6,7}中,与排好序的{1,6,7}数分别进行比较,得到有序{1,6,7,9}
第四次迭代:{1,6,7,9} 3拿出第五数3,插入到排好序的{1,6,7,9}中,与排好序的{1,6,7,9}数分别进行比较,得到有序{1,3,6,7,9}
插入排序例子:有些人打扑克时习惯从第二张牌开始,和第一张牌比较,第二张牌如果比第一张牌小那么插入到第一张牌前面,这样前两张牌都排好序了,接着从第三张牌开始,将它插入到已排好序的前两张牌里,形成三张排好序的牌,后面第四张牌继续插入到前面已排好序的三张牌里,直至排序完。
通过上面例子,相信已经对插入排序有概念上的理解了。
2、通过代码来实现插入排序
package main
import "fmt"
func InsertSort(list []int) {
n := len(list)
// 进行 N-1 轮迭代
for i := 1; i <= n-1; i++ {
//待排序的单元值
deal := list[i]
//待排序左边的单元值
j := i - 1
//左边的值大于待排序的值,那么就需要做比较插入相应位置。
if list[j] > deal {
for ; j >= 0 && list[j] > deal; j-- {
//第一次执行:list[0+1]=list[1]=list[0]
list[j+1] = list[j]
}
//第一次执行:j=-1,list[-1+1]=list[0]=deal,达到下标0值与下标1的值互换效果。
list[j+1] = deal
}
}
}
func main() {
list2 := []int{9, 5, 1, 6, 8, 14, 6, 49, 25, 4, 6, 3}
InsertSort(list2)
fmt.Println(list2)
}
最好情况下,对一个已经排好序的数列进行插入排序,那么需要迭代 N-1 轮,并且因为每轮第一次比较,待排序的数就比它左边的数大,那么这一轮就结束了,不需要再比较了,也不需要交换,这样时间复杂度为:O(n)。
最坏情况下,每一轮比较,待排序的数都比左边排好序的所有数小,那么需要交换 N-1 次,第一轮需要比较和交换一次,第二轮需要比较和交换两次,第三轮要三次,第四轮要四次,这样次数是:1 + 2 + 3 + 4 + ... + N-1,时间复杂度和冒泡排序、选择排序一样,都是:O(n^2)。
因为是从右到左,将一个个未排序的数,插入到左边已排好序的队列中,所以插入排序,相同的数在排序后顺序不会变化,这个排序算法是稳定的。
在有大量元素的无序数列下,这些算法的效率都很低。