java排序之插入排序(直接插入排序和希尔排序)

上面一片博文探讨了关于的java选择排序(冒泡排序和快速排序)本章将继续探讨java排序之插入排序,插入排序分为直接插入排序和希尔排序两种。

1.直接插入排序思想:在需要排序的一组数据中假设前该数组的前n-1(n >= 2)个数是已经排好序的,现在要把第n个数插入到前面的n-1个数中,使得这n个数也是排好顺序的。如此反复进行,知道n等于需要排序的数组的长度时。就实现了该数组的直接插入排序。

代码如下:

/**

*

* @param a 需要排序的数组

*/

public static void simpleSort(int[] a){

for(int i = 1;i<a.length;i++){//外层for循环从1开始

int temp = a[i];

int j = i-1;

for(;j>=0 && temp < a[j];j--){

a[j+1] = a[j];

}

a[j+1] = temp;

}

}

//代码解释:

例如:需要排序的数组int[] a = {49,38,65,97,76,13,27};

第一次执行该方法执行for循环。

i=1,temp=38,j=0,a[j]= 49 38 < 49 满足for(;j>=0 && temp < a[j];j--)条件

执行a[j+1] = a[j]即a[1] = a[0] 执行后数组为a=[49,49,65,97,76,13,27]

执行j--,执行后j=-1 跳出内部for循环

执行a[j+1] = temp; j=-1 因此 a[0] = 38;

完成第一次循环后 数组a=[38,49,65,97,76,13,27]

第二次执行外部循环

i=2,temp=65,j=1,a[j]=49 65 > 49 不满足内部for循环条件直接跳出

执行 a[j+1] = temp; 即a[2]=65

完成第二次循环后 数组a=[38,49,65,97,76,13,27]

第三次外部循环

i=3,temp=97,j=2,a[j]=65 97 > 65 不满足内部for循环条件直接跳出

执行a[j+1] = temp;即a[3] = 97

完成第三次循环后 数组a=[38,49,65,97,76,13,27]

第四次外部循环

i=4,temp=76,j=3,a[j]=97 76 < 97 满足内部for循环条件

执行a[j+1] = a[j];即a[4] = a[3] 执行后数组为a=[38,49,65,97,97,13,27]

执行j--,执行后j=2 a[j]=65 76 > 65 不满足继续执行内部for循环的条件 直接跳出

执行a[j+1] = temp;即a[3] = 76

完成第四次循环后 数组a=[38,49,65,76,97,13,27]

第五次外部循环

i=5,temp=13,j=4,a[j]=97 13 < 97 满足内部for循环条件

执行a[j+1] = a[j];即a[5] = a[4] 执行后数组为a=[38,49,65,76,97,97,27]

执行j--,执行后j=3,a[j]=76 13 < 76 满足内部for循环条件

执行a[j+1] = a[j];即a[4] = a[3] 执行后数组为a=[38,49,65,76,76,97,27]

执行j--,执行后j=2 a[j]=65 13 < 65 满足内部for循环条件

执行a[j+1]=a[j];即a[3] = a[2] 执行后数组a=[38,49,65,65,76,97,27]

执行j--,执行后j=1 a[j]=49 13 < 49 满足内部for循环条件

执行a[j+1]=a[j];即a[2]=a[1] 执行后数组为a=[38,49,49,65,76,97,27]

执行j--,执行后j=0,a[j] = 38,13 < 38 满足内部for循环条件

执行a[j+1]=a[j];即a[1] = a[0] 执行后数组为a=[38,38,49,65,76,97,27]

执行j--,执行后j=-1,不满足内部for循环条件跳出循环

执行a[j+1] = temp;即a[0]=13 执行后数组a=[13,38,49,65,76,97,27]

完成第五次循环 。

依次循环直到跳出外部for循环整个数组排序完成。

2.希尔排序法

2.1实现思想

在直接插入排序算法中,每次插入一个数。使有序序列 只增加几个节点,而且对插入下一个数没有提供任何帮助。如果比较相隔较远(称为增量)的两个数,使得数移动时能跨过多个数,则进行一次比较就可能消除多个元素交换。D.L.Shell于1959年以他的名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按照某个增量d分成若干组,每组中元素的下标相差d。对每组中全部元素进行排序,然后在用一个较小的分量(较小的分量一般取当前分量的一半d/2)对排序后的的 整个数组进行分组。再对每组进行排序。当增量d=1时,整个要排序的数组本分成一个数组,然后进行排序,排序即可完成。

2.2历史背景

直接插入排序它的效率在某些时候是很高的,比如我们的元素本身就是基本有序的,我们只需要少量的插入操作,就可以完成整个数组的排序工作。此时直接插入很高效。还有就是数据比较少时,直接插入的优势也比较明显。可问题在于两个条件本身过于苛刻,现实中数据少和基本有序都属于特殊情况。有条件当然是好的,条件不存在我们创造条件也要去做,于是科学家D.L.Shell研究出一种排序算法,对直接插入排序改进后可以提高效率。

如何然待排序的数据少呢?很容易想到就是将原本有大量数据的数组进行分组,分割成若干个子序列,此时每个子序列的数据就比较少。然后在这些子序列内分别进行直接插入排序,当整个序列都基本有序时,在对全体记录进行一次直接插入排序。问题其实也就在这里,我们分隔待排序数组的目的就是为了减少数据的量,对每个子序列进行直接插入排序就是为了让整个数组基本有序。

例如数组a=[9,1,5,8,3,7,2,4,6]现在将他按前后顺序分为三组a1=[9,1,5],a2=[8,3,7],

a3=[2,4,6],将三个子序列a1,a2,a3排序后重新组合在一起后a=[1,5,9,3,7,8,2,4,6],此时这个数组还是杂乱无序的,根本谈不上基本有序,要排序还是直接重来一遍插入排序。这样做只是瞎子戴眼镜多余的圈圈,毫无用处,所谓基本有序不是局部有序而是小的数据基本在前面,大的的数据基本在后面,不大不小的数据基本在中间,因此我们会发现将一组需要排序的数据按照先后顺序分组排序后满足不了我们的要求。所以我们需要采取跳跃分割的策略:将相距某个“增量”的数据组成一个子序列,这样才能保证在子序列内分别进行插入排序后得到的结果是一个基本有序的数组而不是一个局部有序的数组。

代码实现:

public static void shellSort(int[] a){

int j;

int len = a.length;

for(int d = len >> 1;d > 0;d = d >> 1 ){

for(int i = d;i<len;i++){

int temp = a[i];

for(j = i; j >= d && temp < a[j-d]; j -= d){

a[j] = a[j-d];

}

a[j] = temp;

}

}

}

代码执行解释:

时间: 2024-12-25 19:12:49

java排序之插入排序(直接插入排序和希尔排序)的相关文章

排序算法分析【二】:希尔排序(附Python&amp;C++代码)

希尔排序 也称递减增量排序算法,是插入排序的一种更高效的改进版本.希尔排序是非稳定排序算法. 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 1.插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率: 2.插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位: 算法原理 基础是插入排序,我们先看图,图片动态展示: 这个图太快了还是不知道他在干嘛,在给一张图(图片均来自互联网): 步长选择 希尔排序中步长的选择是重中之重![来自于维基百科] 1.最终步长必

常见排序集合(冒泡排序,选择排序,直接插入排序,二分插入排序,快速排序,希尔排序,归并排序)

一下是一些常见的排序算法: 交换元素(后面算法都有用到): // 交换元素 private static void swap(int[] a, int i, int j) { int temp; temp = a[i]; a[i] = a[j]; a[j] = temp; } 冒泡排序(有优化): // 冒泡排序(优化①,②,③,④) private static void bubbleSort(int[] a) { boolean flag = false;// ①表示整个序列是无序的 for

排序之插入排序:直接插入和希尔排序

一.插入排序 1.思想:原理类似抓扑克牌,在有序表中进行插入和查找,插入合适的位置时,之后的元素需要往后移动 2.时间复杂度: 最好:O(N),正序情况,只有比较时间,无移动时间 最坏:O(N2),逆序情况 平均:O(N2) 3.辅助空间:O(1) 4.稳定性:稳定 5.适用场合:适用于初始序列基本有序的情况,或者n小的时候,插入排序效率高 1 public static void insertSort(int[] a) { 2 int target,i,j; 3 for(j = 1;j<a.l

算法学习之排序算法(四)(希尔排序)

1.算法思想 先将整个待排元素序列分割成若干个子序列(由相隔某个"增量"的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高. 希尔(Shell)排序又称为缩小增量排序,它是一种插入排序.它是直接插入排序算法的一种威力加强版. 希尔排序的基本思想是 把记录按步长 gap 分组,对每组

详谈排序算法之插入类排序(两种思路实现希尔排序)

1. 排序( sorting) 的功能是将一个数据元素的任意序列,重新排列成一个按关键字有序的序列.其确切的定义为: 假设有n个数据元素的序列{R1 , R2 , - , Rn},其相应关键字的序列是{K1 , K2 , - , Kn} ,通过排序要求找出下标 1 , 2 , - , n的一种排列p1 , p2 , - , pn,使得相应关键字满足如下的非递减(或非递增)关系Kp1 ≤ Kp2 ≤ - ≤ Kpn这样,就得到一个按关键字有序的纪录序列{ Rp1 , Rp2 , - , Rpn }

排序---内部排序算法(快排、希尔排序、归并排序、基数排序、冒泡、选择排序)比较

1.内部排序的复杂度总结 1)时间复杂度 4种排序的平均时间复杂度是O(nlog2n),"快些以nlog2n的速度归队"(快排.希尔排序.归并.堆排序) 最坏情况下,快排的时间复杂度为O(n*n) 2)空间复杂度 O(log2n)快排 O(n)归并 O(rd)基数 其他都是O(1) 3)稳定性 不稳定的:"考研复习痛苦啊,情绪不稳定,快些选一堆好友来聊天吧"(快排.希尔.简单选择排序.堆排序) 其他都是稳定的. 4)一趟排序,保证一个关键字到达最终位置 交换类(起泡

基本排序算法(冒泡排序 选择排序 插入排序 快速排序 归并排序 基数排序 希尔排序)

冒泡排序 public static void bubbleSort(int[] arr){ int lgn = arr.length; for (int i = 0; i < lgn - 1; i++) { for (int j = 0; j < lgn - 1 - i; j++) { if(arr[j] > arr[j + 1]){ int temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } } 选择排序 publ

【算法】【排序】【插入类】希尔排序 ShellSort

#include<stdio.h> #include <time.h> #include<stdlib.h> int main(){ int a[15]; //设立随机数 srand(time(0)); for(int i=0;i<15;i++){ a[i]=rand()%(30); //随机数范围0到29之间 } //数组a的大小 int size=sizeof(a)/4; //打印数组信息 for(int i=0;i<size;i++){ printf(

插入排序算法之直接插入排序和希尔排序

插入排序算法 有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法--插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的.个数加一的有序数据. 直接插入排序 直接插入排序的排序思路是:每次将一个待排序的元素与已排序的元素进行逐一比较,直到找到合适的位置按大小插入. 例子: 有序列: 开始时,有序序列只有一个元素就是第一个元素(红色),后面的无序序列(绿色).接下来,取无序序列中

算法之直接插入排序和希尔排序

1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表.即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止. 要点:设立哨兵,作为临时存储和判断数组边界之用. 直接插入排序示例: 如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面.所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是