排序之插入排序|Go主题月

437 阅读2分钟

插入排序:

  1. 它在列表较低即列表的头部一端维护一个有序的 子列表,并逐个将每个新元素“插入”这个子列表。
  2. 首先假设位置 0 处的元素是只含单个元素的有序子列表。
  3. 从元素 1 到元素 n–1,每一轮都将 当前元素与有序子列表中的元素进行比较。
  4. 在有序子列表中,将比它大的元素右移;当遇到一个比它小的元素或抵达子列表起点(索引为0)时,就可以插入当前元素。

以[10, 1, 5, 3]的切片数组为例,按照插入排序算法进行升序排序,排序过程如下图(带颜色方框为有序子列表):

  1. 把10视为只有一个元素的有序子列表;
  2. 在有序子列表[10]中插入1,因为要保持子列表有序,所以1需要和有序子列表中的元素进行比较(从尾部开始比较),因为10比1大,所以需要把10右移。此时,已抵达子列表起点,就可以插入当前元素1;
  3. 在有序子列表[1, 10]中插入5, 因为要保持子列表有序,所以5需要和有序子列表中的元素进行比较(从尾部开始比较),因为10比5大,所以需要把10右移。继续和有序子列表中的下一个元素1比较,因为1比5小,就可以插入当前元素1;
  4. 在有序子列表[1, 5, 10]中插入3, 因为要保持子列表有序,所以3需要和有序子列表中的元素进行比较(从尾部开始比较),因为10比3大,所以需要把10右移。继续和有序子列表中的下一个元素5比较,因为5比3大,所以需要把5右移;继续和有序子列表中的下一个元素1比较,因为1比3小,就可以插入当前元素3;
  5. 此时,已排序完毕,结果为[1, 3, 5, 10]

插入.png

时间复杂度:O(n²)
从上面的排序过程中,给n个元素的切片数值插入排序需要经过n-1次遍历,然后每次遍历的比较次数依次为2、3、4、5、...、n-2、n-1,所以是2+3+...+n-2+n-1的和,即½n²-½n-1,即O(n²)。但是由于每次只是进行赋值并非完整交换,赋值的速度较交换更快,所以较选择排序,插入排序更快一点。

使用Golang实现的插入排序算法代码如下:

package main

import "fmt"

func insertSort(numList []int) {
	for idx := 1; idx < len(numList); idx++ {
		value := numList[idx]
		position := idx

		for position > 0 && numList[position-1] > value {
			numList[position] = numList[position-1]
			position -= 1
		}

		numList[position] = value
	}
}

func main() {
	numList := []int{10, 1, 5, 3}
	fmt.Println(numList)
	// [10 1 5 3]
	insertSort(numList)
	fmt.Println(numList)
	// [1 3 5 10]
}