插入排序
主要操作是插入,其基本思想是:每次将一个待排序的记录按其关键码的大小插入到一个已经排好序的有序序列中,直到全部记录排好序为止。
插入排序的分类:
- 直接插入排序
- 折半插入排序
- 希尔排序
一、插入排序
1、思路:
初始时把第一个数看成一个有序数列,把 r[ 0 ]=剩下的数列的第一个数,与有序数列的最后一个数比较;
如果这个数大于有序数列的最后一个数,那么这个数不动(加入了有序数列);
如果小于,那么有序数列的最后一个数向后移动一位,再与有序数列的倒数第二个数比较,知道这个数大于有序数列的数,否则被比较的有序数列数字后移。
一直重复这个动作。
2、代码
void insertsort(int r[],int n)
{
int i,j;
for(i=2;i<=n;i++)
{
r[0]=r[i];
j=i-1;
while(r[0]<r[j])
{
r[j+1]=r[j];
j--;
}
r[j+1]=r[0];
}
}
int main()
{
int a[13]={0,12,67,56,16,25,22,48,34,43,68,1,23}; //a[0]不存数据
insertsort(a,12);
for(int j=1;j<=12;j++)
printf("%d ",a[j]);
return 0;
}
3、性能
最好 O(n)
最坏:O(n2)
时间复杂度:O(n2)
直接插入排序算法简单、容易实现,适用于待排序记录基本有序或待排序记录较小时。
二、折半插入排序
1、思想
是直接插入排序的改进
对于第i个插入点,可以对前有序的 i-1 序列进行折半查找,减少比较次数。
步骤与直接插入排序一样
- 暂存待插记录
- 查找插入位置
- 后移记录
- 插入待插记录
2、代码
void BinaryInsertsort(int r[],int n)
{
int i,j,mid,low,high;
for(i=2;i<=n;i++)
{
r[0]=r[i];
low=1; high=i-1;
while(low<=high)
{
mid=(low+high)/2;
if(r[mid]>r[0])
high=mid-1;
else
low=mid+1;
}
for(j=i-1;j>=high+1;j--)
r[j+1]=r[j];
r[high+1]=r[0];
}
}
3、性能
减少了关键字的比较次数,但记录的移动次数并未减少
时间复杂度为 O(n*2)
三、希尔排序
直接插入排序的改进:
- 若待排序记录按关键码基本有序时,直接插入排序的效率可以大大提高;
- 由于直接插入排序算法简单,则在待排序记录数量n较小时效率也很高。
1、思想(分治思想)
将整个待排序记录分割成若干个子序列,在子序列内分别进行直接插入排序,
待整个序列中的记录基本有序时,对全体记录进行直接插入排序。
- 分割的组数:数据数 / 2 , 注意组内元素是分隔的。
- 直接插入排序每次移动一位,希尔排序每次移动 d 位
2.代码
void Shellsort(int r[],int n) //希尔排序,r[0]不存数据
{
int d,i,j;
for(d=n/2;d>=1;d=d/2)
{
for(i=d+1;i<=n;i++)
{
r[0]=r[i];
j=i-d;
while(j>0 && r[0]<r[j])
{
r[j+d]=r[j];
j=j-d;
}
r[j+d]=r[0];
}
}
}
3.性能
时间复杂度:O(n*2) ~ O(nlogn)之间