假设你在玩扑克牌,你要把牌按从小到大排列。当你拿到第一张牌,那它就是最小的,把它放在第一个位置上。当你拿到第二张牌,你和第一张牌做比较,如果它大于第一张牌,则把它放到第一张牌的右边,反之则放到左边。当你拿到第三张牌,你拿它和第二个位置上的牌比较,然后如有必要需要和第一个位置上的牌比较。然后是第四张牌……最后,一手牌就按从小到大的顺序排好了。这就是插入排序。
但是实际使用排序算法时一般是给定一组数据进行排序,和上述情况唯一不同的是我们要先取出一个作为需要插入的元素。
代码实现
考虑对一个n元数组排序
main.c
#include "insertion_sort.h"int main(){ int a[10] = {50, 3, 47, 23, 9, 18, 34, 2, 16, 10}; print_array(a, sizeof(a)/sizeof(int)); insertion_sort(a, sizeof(a)/sizeof(int)); print_array(a, sizeof(a)/sizeof(int)); return 0;}
insertion_sort.h
#include #include void insertion_sort(int a[], int num);void print_array(int a[], int num);
insertion_sort.c
#include "insertion_sort.h"/*why count is needed?*//*Because array is passed as a pointer through value parameter*/void insertion_sort(int a[], int count){ for (int i = 1; i < count; i++)//the first element needn't change { int tmp = a[i];//a[i] is the element to be inserted for (int j = i-1; j >=0 && a[j]>tmp; j--) { a[j+1] = a[j];//make the place for a[i] a[j] = tmp; } printf("after round %d: ",i); print_array(a, count); }}void print_array(int a[], int count){ for (int i = 0; i < count; i++) { printf("%d ",a[i]); } printf("");}
编译运行
gcc insertion_sort.c main.c -o insertion_sort.exe
$ ./insertion_sort.exe50 3 47 23 9 18 34 2 16 10after round 1: 3 50 47 23 9 18 34 2 16 10after round 2: 3 47 50 23 9 18 34 2 16 10after round 3: 3 23 47 50 9 18 34 2 16 10after round 4: 3 9 23 47 50 18 34 2 16 10after round 5: 3 9 18 23 47 50 34 2 16 10after round 6: 3 9 18 23 34 47 50 2 16 10after round 7: 2 3 9 18 23 34 47 50 16 10after round 8: 2 3 9 16 18 23 34 47 50 10after round 9: 2 3 9 10 16 18 23 34 47 502 3 9 10 16 18 23 34 47 50
动态示意
复杂度
可以看到插入排序也是由两层循环嵌套而成,外层循环n-1次,内层循环则视情况而定:
- 最优情况是数组顺序已好,内层循环运行在O(1)
- 最坏情况是数组反序,内层循环运行在O(n)
因此,最优情况为O(n),最坏情况为O(n^2)
参考链接
https://visualgo.net/zh/sorting