一、什么是插入排序?
每次讲一个待排序的元素,按其关键字的大小插入到已排好序的表中,直到全部元素插入完成为止。这里默认为增序。
二、常见的插入排序
(1)、直接插入排序
设数组为a[0…n],步骤如下:
1. 将原序列分成有序区和无序区,其中a[0…i-1]为有序区,a[i…n] 为无序区(i从1开始);
2. 从无序区中取出第一个元素,即a[i],在有序区序列中从后向前扫描;
3. 如果有序元素大于a[i],将该有序元素后移到下一位置;
4. 重复步骤3,直到找到小于或者等于a[i]的有序元素,将a[i]插入到该有序元素的下一位置中;
5. 重复步骤2~4,直到无序区元素为0。
可通过下面的动态图来理解:
代码如下:
void InsertSort(int seq[],int n){
int i,j;
int temp;
for(i=1;i<n;i++){
temp=seq[i]; //要插入的数据
j=i-1;
while(j>=0&&seq[j]>temp){
seq[j+1]=seq[j]; //后移
j--;
}
seq[j+1]=temp;
}
}
(2)、二分插入排序
设数组为a[0…n],步骤如下:
1. 将原序列分成有序区和无序区,a[0…i-1]为有序区,a[i…n] 为无序区(i从1开始);
2. 从无序区中取出第一个元素,即a[i],使用二分查找算法在有序区中查找要插入的位置索引j;
3. 将a[j]到a[i-1]的元素后移,并将a[i]赋值给a[j];
4. 重复步骤2~3,直到无序区元素为0。
代码如下:
void InsertSort(int seq[],int n){
int i,j,low,high,mid;
int temp;
for(i=1;i<n;i++){
temp=seq[i];
high=i-1;
//该while循环用于查找temp应该插入的位置
//在本次while循环的最后一次循环时,low==high==mid,接着要么if,要么else,
while(low<=high){
mid=(low+high)/2;
if(temp<seq[mid]){
high=mid-1;
}
else{
low=mid+1;
}
}
for(j=i-1;j>=high+1;j--){
seq[j+1]=seq[j];
}
seq[high+1]=temp;
}
}
上述程序中,for循环嵌套这while循环,在while循环的最后一次循环时,low=mid=high,接着要么if,要么else,如下图所示,
若if,则意味着该未排序的元素应该插入到mid位置的前一个位置,即high=mid-1处,而此时的high<mid,故结束while循环;
若else,则意味着该未排序的元素应该插入到mid位置的后一个位置,即low=mid+1处,而此时的high<mid,故结束while循环。
因此,在结束while循环后,都应该将此时的high(不包括high)以后的元素往后移一位。
(3)、希尔排序(ShellSort)
基本思想:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。
先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),
即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。
可参考这里的动画来理解。http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/shell.htm
代码如下:
void ShellSort(int R[],int n){
int gap,i,j,temp;
gap=n/2;
for(i=gap;i<n;i++){
j=i-gap;
temp=R[i];
while(j>=0&&temp<R[j]){
R[j+gap]=R[j];
j=j-gap;
}
R[j+gap]=temp;
}
gap=gap/2;
}
参考:http://student.zjzk.cn/course_ware/data_structure/web/paixu/paixu8.2.2.1.htm
http://www.cnblogs.com/heyuquan/p/insert-sort.html