一.直接插入排序(Straight Insertion Sort)
1.基本思想
插入排序的基本操作就是将一个数据插入到已经排好序的有序数组中,从而得到一个新的、个数加一的有序数组。比较和交换的时间复杂度为O(n^2),算法自适应,对于数据已基本有序的情况,时间复杂度为O(n),算法稳定,开销很低。算法适合于数据已基本有序或者数据量小的情况。
2.思路
先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。
3.代码
/**
* 方法名:InsertSort
* 详述:插入排序
* 核心思想:
*/
public static void InsertSort(int numbers[]){
for(int i=1;i<numbers.length;i++){ //循环从第二个数组元素开始,因为arr[0]作为最初已排序部分
int sentinel = numbers[i]; //哨兵 将该元素取出来
int j = i-1;
for(; (j>=0) && (numbers[j]>sentinel);j--){ //将sentinel与已排序元素从小到大比较,寻找sentinel应插入的位置
numbers[j+1] = numbers[j]; //将元素往后移
}
numbers[j+1] = sentinel;
}
}
测试:
@Test
public void testInsertSort(){
int numbers[]={49,38,65,97,76,13,27};
AllSorts.InsertSort(numbers);
AllSorts.printArr(numbers);
}
结果:
13 27 38 49 65 76 97
4.优缺点
(1)优点
稳定,快
(2)缺点
比较次数不一定,比较次数越少,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决 这个问题。
二.折半插入
1.基本思想
折半插入排序(binary insertion sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
要点:在查找插入位置上的优化,速度上稍微有了一定的提升,虽然在乱序的数据上有良好的效果,但是时间复杂度仍然很大O(n^2)。是稳定的算法。
2.思路
先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,查找插入的时候采用二分查找法即根据mid( (high+low)/2 )查找记录应该在的位置,进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。
3.代码
/**
* 方法名:BinaryInsertSort
* 详述:折半插入排序
* 核心思想:
*/
public static void BinaryInsertSort(int numbers[]){
for (int i = 1; i < numbers.length; i++){
int sentinel = numbers[i];
int low = 0;
int high = i - 1;
while (low <= high){
int mid = (low + high) / 2;
if (sentinel < numbers[mid])
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
for (int j = i - 1; j > high; j--){
numbers[j + 1] = numbers[j];
}
numbers[high + 1] = sentinel; // 或者data[low] = temp;
}
}
测试:
@Test
public void testBinaryInsertSort(){
int numbers[]={49,38,65,97,76,13,27};
AllSorts.BinaryInsertSort(numbers);
AllSorts.printArr(numbers);
}
结果:
13 27 38 49 65 76 97
4.优缺点
(1)时间复杂度
折半插入排序比直接插入排序明显减少了关键字之间的比较次数,但是移动次数是没有改变。所以,折半插入排序和插入排序的时间复杂度相同都是O(N^2),在减少了比较次数方面它确实相当优秀,所以该算法仍然比直接插入排序好。
(2)空间复杂度
折半插入排序和插入排序一样只需要一个多余的缓存数据单元来放第 i 个元素,所以空间复杂度是O(1),因为排序前2个相等的数在序列的前后位置顺序和排序后它们两个的前后位置顺序相同,所以它是一个稳定排序。
三.希尔排序(Shell`s Sort)
1.基本思想
希尔排序核心仍然是基于插入方式的,以逐步减小“步长”,采用“分治”的思想对每一个子序列进行排序。最终实现对整个序列的排序。
即先将整个待排序的记录序列按照增量increment分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
2.思路
(1)将数的个数设为n,取奇数k=n/2,将下标差值为k的书分为一组,构成有序序列。
(2)再取k=k/2 ,将下标差值为k的书分为一组,构成有序序列。
(3)重复第二步,直到k=1执行简单插入排序。
3.代码
/**
* 方法名:ShellSort
* 详述:希尔排序
* 核心思想:
*/
public static void ShellSort(int numbers[]){
int increatment = numbers.length/2;
while(increatment>=1){
for(int i=0;i<increatment;i++){
for (int j = i; j < numbers.length; j+=increatment) {
if(j>=increatment){
int sentinel = numbers[j];
int k = j - increatment ;
for (; (k>=0) && (numbers[k]>sentinel); k-=increatment) {
numbers[k+increatment] = numbers[k];
}
numbers[k+increatment] = sentinel;
}
}
}
increatment/=2;
}
}
测试:
@Test
public void testShellSort(){
int[] numbers = {1,3,10,5,18,9,4,2,6,8,7};
AllSorts.ShellSort(numbers);
AllSorts.printArr(numbers);
}
结果:
1 2 3 4 5 6 7 8 9 10 18
4.优缺点
希尔排序是不稳定的排序算法,会导致数据原始相对位置的改变。如果以步长为2计算,其时间复杂度可达到O(n^2),若数据足够长,步长也足够大那么时间复杂度将接近与O(n),但是一般认为其为O(n^1.3)。
833

被折叠的 条评论
为什么被折叠?



