基本思路:
将一个记录插入到已经排好序的有序表中,得到一个新的、长度加一的有序表
使用的结构:
#define MAX 10
//排序所用的顺序表结构
typedef struct
{
int a[MAX+1]; //存储排序数组,a[0]用作临时变量
int length; //记录顺序表的长度
}Sqlist;
//交换
void swap(Sqlist *L,int i,int j)
{
int t=L->a[i];
L->a[i]=L->a[j];
L->a[j]=t;
}
算法:
void InsertSort(Sqlist *L)
{
int i,j;
for(i=2;i<=L->length;i++) //i从2开始
{
if(L->a[i]<L->a[i-1]) //将L->a[i]插入有序序列
{
L->a[0]=L->a[i]; //用a[0]存储a[i]的值
for(j=i-1;L->a[j]>L->a[0];j--) //注意for循环的各种条件
L->a[j+1]=L->a[j]; //记录后移
L->a[j+1]=L->a[0]; //将a[i]插入到正确的位置
}
}
}
代码解析:
假设我们的参数L中length=6,a[6]={0,5,3,4,6,2},其中a[0]用作临时变量。
第4行代码的for循环i从2开始意为:我们假设a[1]=5已经是放好位置的元素,所以后面的操作本质上就是以a[1]为中心,插入到它的左边或者右边(较大的在右,较小的在左)
第6行代码,i=2,L->a[2]=3小于L->a[1]=5,故继续执行if内的语句
第8行代码,a[0]存储a[i]有两个作用,一个是作为第10行的for循环的终止条件,其二是便于第13行的a[i]的插入
第10行代码,for循环就是一个个判断目前的元素a[i]的左边的元素是否大于目前的元素,若大于,则左边的这一个元素往右移动一个位置。一直往左边遍历,直到找到有元素小于目前的元素a[i]或者已经遍历完了第一个元素,此时退出循环
退出该循环后,下一条语句将a[i]插入到正确的序列位置
进行第二次外层for循环,此时经过上次循环后a[1]=3,a[2]=5。而后i=3,L->a[3]=4小于L->a[2]=5,故执行if内的语句,
结果是a[3]插入到a[1]于a[3]之间变成了a[2]
此后重复步骤......
复杂度
最好的情况下,主要是执行第6行的if语句比较,由于有序,每次的if都不成立故无元素的移动,时间复杂度O(n)
最坏的情况下,逆序表,比较次数:2+3+...+n=(n+2)(n-1)/2次
移动次数:(n+4)(n-1)/2次
平均比较和移动次数:(n^2)/4
综上,时间复杂度为O(n^2)