插入排序,通常咱们指的是简单插入排序,也能够叫直接插入排序。就是说,每次把一个数插到已经排好序的数列里面造成新的排好序的数列,以此反复。算法
插入排序属于插入类排序算法。segmentfault
除了我之外,有些人打扑克时习惯从第二张牌开始,和第一张牌比较,第二张牌若是比第一张牌小那么插入到第一张牌前面,这样前两张牌都排好序了,接着从第三张牌开始,将它插入到已排好序的前两张牌里,造成三张排好序的牌,后面第四张牌继续插入到前面已排好序的三张牌里,直至排序完。数组
举个简单例子,插入排序一个 4 个元素的数列:4 2 9 1
:数据结构
[]表示排好序 第一轮: [4] 2 9 1 拿待排序的第二个数 2,插入到排好序的数列 [4] 与排好序的数列 [4] 比较 第一轮进行中:2 比 4 小,插入到 4 前 第二轮: [2 4] 9 1 拿待排序的第三个数 9,插入到排好序的数列 [2 4] 与排好序的数列 [2 4] 比较 第二轮进行中: 9 比 4 大,不变化 第三轮: [2 4 9] 1 拿待排序的第四个数 1,插入到排好序的数列 [2 4 9] 与排好序的数列 [2 4 9] 比较 第三轮进行中: 1 比 9 小,插入到 9 前 第三轮进行中: 1 比 4 小,插入到 4 前 第三轮进行中: 1 比 2 小,插入到 2 前 结果: [1 2 4 9]
最好状况下,对一个已经排好序的数列进行插入排序,那么须要迭代N-1
轮,而且由于每轮第一次比较,待排序的数就比它左边的数大,那么这一轮就结束了,不须要再比较了,也不须要交换,这样时间复杂度为:O(n)
。并发
最坏状况下,每一轮比较,待排序的数都比左边排好序的全部数小,那么须要交换N-1
次,第一轮须要比较和交换一次,第二轮须要比较和交换两次,第三轮要三次,第四轮要四次,这样次数是:1 + 2 + 3 + 4 + ... + N-1
,时间复杂度和冒泡排序、选择排序同样,都是:O(n^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 deal < list[j] { // 一直往左边找,比待排序大的数都日后挪,腾空位给待排序插入 for ; j >= 0 && deal < list[j]; j-- { list[j+1] = list[j] // 某数后移,给待排序留空位 } list[j+1] = deal // 结束了,待排序的数插入空位 } } } func main() { list := []int{5} InsertSort(list) fmt.Println(list) list1 := []int{5, 9} InsertSort(list1) fmt.Println(list1) list2 := []int{5, 9, 1, 6, 8, 14, 6, 49, 25, 4, 6, 3} InsertSort(list2) fmt.Println(list2) }
输出:性能
[5] [5 9] [1 3 4 5 6 6 6 8 9 14 25 49]
数组规模n
较小的大多数状况下,咱们可使用插入排序,它比冒泡排序,选择排序都快,甚至比任何的排序算法都快。code
数列中的有序性越高,插入排序的性能越高,由于待排序数组有序性越高,插入排序比较的次数越少。协程
你们都不多使用冒泡、直接选择,直接插入排序算法,由于在有大量元素的无序数列下,这些算法的效率都很低。
我是陈星星,欢迎阅读我亲自写的 数据结构和算法(Golang实现),文章首发于 阅读更友好的GitBook。