一、插入排序
1.1 直接插入排序(边比较边移动元素)
基本思想:把第一个元素当做已排好的序列,从第二个元素开始在原数组的基础上进行就地排序。
直接插入排序适用于基本有序和数量不大的排序表。
void Insert_sort(int[] array){
int tmp = array[0];
for(int i=1; i<array.length; i++){
tmp = array[i];
int j;
for(j=i-1; j>=0; j--){
if(tmp < array[j]){
array[j+1] = array[j];
}
else {
break;
}
}
array[j+1] = tmp; //插入待排元素
}
}
/*
* 时间复杂度:
* 最坏情况:O(n^2) 最好情况(有序时):O(n)
* 空间复杂度:O(1)
* 稳定性:稳定
*/
1.2 折半插入排序(先比较再移动元素)
基本思想:先利用折半查找的方式找到待插入元素的位置,再统一移动元素。
相比较于直接插入排序,折半插入排序只是减少了比较次数,并没有减少元素的移动次数。
void Binary_sort(int[] array){
int i, j;
for(i=1; i<array.length; i++){
int left = 0;
int right = i;
int tmp = array[i]; //记录当前待排元素的值
//先在当前范围内查找待插入元素的位置(left==right时,找到待插入位置)
while(left < right){
int mid = (left+right)/2;
//左闭右开
if(tmp < array[mid]){
right = mid-1;
}
else{
left = mid+1;
}
}
//搬移:移动待插入位置之后的元素
for(j=i; j>right; j--){
array[j] = array[j-1];
}
//插入(right为待插入元素的位置)
array[right] = tmp;
}
}
/*
* 时间复杂度:
* 最坏情况:O(n^2) 最好情况(有序时):O(n)
* 空间复杂度:O(1)
* 稳定性:稳定
*/
1.3 希尔排序(又称缩小增量法,是对直接插入排序的优化)
基本思想:先选定一个整数gap,把待排序中所有元素分组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,重复上述分组和排序的工作。当到达gap=1时,所有元素再进行一次直接插入排序。
注:必须保证最后一个增量为1。
void Shell(int[] array, int gap){
//从第一个间隔gap的元素开始
for(int i=gap; i<array.length; i++){
int tmp = array[i];
//对gap位置的元素进行直接插入排序
int j;
for(j=i-gap; j>=0; j-=gap){
if(tmp < array[j]){
array[j+gap] = array[j];
}
else{
break;
}
}
//因为在循环中,j-=gap后判断条件不合适才停止因此待插入元素的下标为j+gap
array[j+gap] = tmp;
}
}
void Shell_sort(int[] array){
//随着增量的增大,排序速度越来越快
int[] gap = {5,3,1};
for(int i=0; i<gap.length; i++){
Shell(array, gap[i]);
}
}
/*
* 时间复杂度:
* 最坏情况:O(n^1.3) 最好情况(有序时):O(n)
* 空间复杂度:O(1)
* 稳定性:不稳定
*/