排序算法之插入排序

204 阅读2分钟

插入排序的工作原理

插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序

因为每次都是在已排好序的数列中找可以插入的合适位置,所以叫做插入排序。

下面👇我画了一张图,来描述选择排序的基本过程。

插入排序.gif

  1. 首先,准备一个乱序的整型数组,[6,3,5,7,1,9,2,8,4],我们对其进行从小到大的排序;
  2. 先进行第一次循环,3和6进行比较,3比6小,所以3应该插在6的前面,因为我们是原地排序,所以就让3和6进行交换即可;
  3. 接着再看3前面还有没有元素,没有,所以本轮循环结束,得到了[3,6,5,7,1,9,2,8,4],前两个数字是有序的了;
  4. 接着再比较5和6,5比6小,同样的,5应该插入6的前面,所以5和6就行交换,得到[3,5,6,7,1,9,2,8,4]
  5. 再然后,5前面还有元素,继续向前比较,发现5比3大,所以本轮循环就结束了;
  6. 后面的元素按照上述步骤依次执行;
  7. 最终,得到一个从小到大顺序排列的数组,[1,2,3,4,5,6,7,8,9]

代码实现(golang)

package main

import "fmt"

// InsertSort 插入排序
func InsertSort(in []int) {
   inLen := len(in)
   for i := 0; i < inLen-1; i++ {
      tmp := in[i+1]
      j := i + 1
      for j > 0 && tmp < in[j-1] {
         in[j] = in[j-1]
         j--
      }
      if i+1 != j {
         in[j] = tmp
      }
   }
}

// 交换数据
func swap(in []int, i int, j int) {
   tmp := in[i]
   in[i] = in[j]
   in[j] = tmp
}

func main() {
   arr := []int{6, 3, 5, 7, 1, 9, 2, 8, 4}
   InsertSort(arr)
   fmt.Println(arr)
}

以上就是最简单的插入排序的代码实现。 根据图解中的流程,我们可以看到arr[4]=1这个元素在进行排序时,和前面的4个元素都进行了三个步骤,分别是:比较、交换、移动指针,这其中也有优化的点,那就是可以将交换放到最后,也就是说,用一个临时变量tmp来存储arr[4]=1的值,大致过程是这样的:

  1. 1和前一个元素7比较,7比1大,则7移动到原来1的位置,7的位置就空出来了;
  2. 1再和前一个元素5比较,5比1大,则5移动到原来7的位置,5的位置就空出来了;
  3. 1再和前一个元素3比较,3比1大,则3移动到原来5的位置,3的位置就空出来了;
  4. 1再和前一个元素6比较,6比1大,则6移动到原来3的位置,6的位置就空出来了;
  5. 最后,将tmp的值赋值给arr[0]。 以上,就可以节省一些交换以及移动指针的步骤。具体代码实现如下:
package main

import "fmt"

// InsertSort 插入排序
func InsertSort(in []int) {
   inLen := len(in)
   for i := 0; i < inLen-1; i++ {
      tmp := in[i+1]
      lastIndex := i + 1
      for j := i + 1; j > 0 && tmp < in[j-1]; j-- {
         in[j] = in[j-1]
         lastIndex = j - 1
      }
      if lastIndex != i+1 {
         in[lastIndex] = tmp
      }
   }
}

// 交换数据
func swap(in []int, i int, j int) {
   tmp := in[i]
   in[i] = in[j]
   in[j] = tmp
}

func main() {
   arr := []int{6, 3, 5, 7, 1, 9, 2, 8, 4}
   InsertSort(arr)
   fmt.Println(arr)
}

时间复杂度

插入排序因为也进行了两次循环,所以它的时间复杂度也是O(n²)