插入算法的基本思想是:每次将一个待排序的记录,按照其关键字的大小插入到前面
已经排好序的子表中的合适位置,直到全部记录插入完成位置,下面介绍一下直接插
入排序、二分插入排序及希尔排序。
直接插入排序:设待排序的记录存放在数组R[0..n-1]中,排序过程的某一中间时刻,
R被分成两个子区间R[0..i-1]和R[i..n-1],前一个是已经排好顺序的有序区,后面
是无序区。直接插入排序的基本操作是将当前无序区的第一个记录R[i]插入到有序
区 R[0..i-1]的合适位置,使R[0..i]变为新的有序区。代码如下:
public class ZhiJieSort {
public static void main(String args[]){
int i ;
int a[] = {2,1,5,6,8,4,3};
insertSort(a, a.length);
System.out.println("排序后:");
for( i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
public static void insertSort(int a[],int n){
int i,j,temp;
for(i=1;i<n;i++){
temp=a[i];
j=i-1;
while(j>=0 && temp<a[j]){
a[j+1] = a[j];
j--;
}
a[j+1] = temp;
}
}
}
表出态是正序的时候时间复杂度最小O(n),表初态为反序时,时间复杂度最大O(n2),
直接插入排序中只用到了i,j,temp三个辅助变量,与问题规模无关,所以空间复杂度
是O(1),直接插入排序是稳定的排序方法 。
二分插入排序:由于插入排序是在有序子表中进行查找和插入的,查找方法可以使用
二分查找来提高查找效率。仅查找记录位置的方法不同,其余跟直接插入思想一致。
代码如下:
public class ErFenSort {
public static void main(String[] args){
int i;
int a[] = {2,8,6,1,4,5,9};
insertSort(a, a.length);
for(i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
public static void insertSort(int a[],int n){
int i,j,low,mid,high,temp;
for(i=1;i<n;i++){
temp=a[i];
low = 0;
high = i-1;
while(low<=high){
mid = (low+high)/2;
if(temp<a[mid]){
high = mid-1;
} else{
low = mid+1;
}
}
for(j=i-1;j>=high+1;j--){
a[j+1]= a[j];
}
a[high+1] = temp;
}
}
}
二分插入排序的空间复杂度为O(1),二分插入排序只是减少了关键字的比较次数,
记录的移动次数并没有改变,因此时间复杂度仍为O(n2)。
希尔排序:实际是一种分组插入方法,基本思想是先取一个小于n的整数d1作为第
一个增量,把表的全部记录分成d1组,所有距离为d1的倍数的被分在同一组,在
各组内进行直接插入排序;然后取第二个增量d2(<d1)重复上面的分组和排序,
直至增量为1,即所有记录放在同一组中进行直接插入排序为止。代码如下:
public class ShellInsert {
public static void main(String[] args){
int a[] = {2,4,3,6,7,9,1,8};
shellInsert(a, a.length);
for(int i =0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
public static void shellInsert(int a[],int n){
int i,j,gap,temp;
gap = n/2;
while(gap>0){
for(i =gap;i<n;i++){
temp = a[i];
j = i-gap;
while(j>=0 && temp<a[j]){
a[j+gap]=a[j];
j = j-gap;
}
a[j+gap] = temp;
}
gap = gap/2;
}
}
}
希尔排序是不稳定的排序算法,时间复杂度为O(n1.3),空间复杂度为O(1),
通常情况下速度比直接插入排序快。