当前位置: 代码迷 >> 综合 >> 排序算法之直接插入、希尔排序、堆排序三者比较
  详细解决方案

排序算法之直接插入、希尔排序、堆排序三者比较

热度:96   发布时间:2023-09-19 06:03:54.0

       最近又研究了一下排序算法,突然发现这些算法大多都是在一些基础上进行的改进,将时间或空间复杂度降低,今天lz先就直接插入、希尔排序、堆排序这三个算法唠叨唠叨。

     先就最简单的直接插入算法说一说:
           直接插入:个人感觉核心便是临时变量角标后移

           啥都不说了,先上代码:

      public static void main(String[] agrs){int[] arrs = new int[]{23,12,41,54,32,43,21};for(int i = 1;i<arrs.length ;i++){//核心之一:定义一个临时变量,用来保存将要插入的值,因为用来比较所以这个值要超然起来//a                int temp = arrs[i];	//这个j必须放在这里,下面的这句arrs[j]=temp赋值,需要的是j,如果定义在for里面,那么便//得不到这个j正确的值了int j;for(j = i;j>0;j--){if(arrs[j-1] > temp){//核心之二:如果要插入的数据大于数组当前角标的数据//那么就将所有的角标统一后移一个单位,否则跳出arrs[j] = arrs[j-1];}else{break;}}//当前的角标便是需要插入的数据点arrs[j] = temp;}//bfor(int i : arrs){System.out.println(i);}}	打印结果:12,21,23,32,41,43,54
       希尔排序:个人感觉核心便是数组的分组直接插入

int[] arrs = new int[]{21,32,43,54,31,78,65,42};//核心之一:对总体数组进行循环分组,每一次间隔数目(也叫冲量)按照上一次
for(int i = arrs.length / 2; i >0 ; i = i / 2){//当前的一次循环便是按照间隔数目划分的所有数组,这里也算是一个核心
//需要比较的分组中,第一组的第一个数是arrs[0],最后一个数据是j
// j即是0+i,那么第二组中第一个数是arrs[1],最后一个是1+i
//所以在下面的循环中j的值直接取i,每一次++
for(int j = i; j<arrs.length ; j++){//每一次数组排序完成后指向下一组数组//aint temp = arrs[j];int p ;//当前的for中,每一次for都是一个数组,在这里需要插入的数往往都是以arrs[j]//那么现在需要进行排序,所以便是核心之二直接插入
//注意此时就是当前的角标和-i的角标数据进行比较
//直接插入的目的是将两个数值互换,那么在这里i是一个间隔数,相当于普通
//直接插入中的一个间隔,所以在这里p=p-i,p>=i(i取不到0,因为第一个循环已经限制了)
for(p = j ; p >= i ;p = p-i){if(temp < arrs[p - i]){arrs[p] = arrs[p - i];}else{break;}}arrs[p] = temp;}
//b
}
        堆排序:核心点-- 构造一个堆堆顶数据互换

               int[] arrs = new int[]{32,21,54,88,64,32,43,54,76,87,98,8723};//n为数据总的长度,堆也是一个可以用数组表示的//此处堆的定义是父节点大或等于所有子节点,那么必须构造一个完整的堆//根据定义,我们如果从上面将数组转换为堆的话,不太合适,因为如果转换下来的上去的父节点
依旧小于更上一层的父节点,那么我们是没办法的,因为是向下生成的
//所以只有从下生成一个堆,拿到最后一个节点,然后向上每一个节点都进行判断,先向上,如果有
子节点,那么当for向上每一个节点移动时,create也在递归中,即向下不断的进行判断,直到最后一个root节点被简
执行到,然后再进行一次总的向下
for(int n = arrs.length/2 - 1;n>=0;n--){//length*2+1即就是最后一个节点,注意数组+1create(arrs,n,arrs.length);}for(int i = arrs.length-1; i>0 ; i--){getMax(arrs, i);}for (int i : arrs) {System.out.print(i+"_");}

public static void create(int[] arrs, int root, int all){int m = 2*root+1;//判断有没有子节点if(m<all){//有左子节点if((m+1)<all){//有右子节点if(arrs[m] < arrs[m+1]){//那么右子节点大,标记右m = m+1;}}//判断父节点和左或者右子节点谁大if(arrs[root] < arrs[m]){int temp = arrs[root];arrs[root] = arrs[m];arrs[m] = temp;//交换后不能明确,交换后的子节点是否是比孙节点还大,所以需要递归判断//传递的数值肯定是大的一方,左或者右子节点
//递归的目的便是不断的向下判断
create(arrs, m, all);}	}else{return;}}

public static void getMax(int[] arrs, int all){//将第一个和最后一个互换int temp = arrs[all];arrs[all] = arrs[0];arrs[0] = temp;//此时需要向下判断,但因为比较完整,向下判断的时候不会出现,变换后的父节点还会比祖节点
大,所以只用一只向下判断即可完善新的堆
create(arrs, 0, all);}

       前面两个算法a 以上的那段for循环,你可以理解成是一个不断拿取将要插入数组数据的数据集,在希尔排序中这个for相当于数组分组完毕后每一个数组中间数据的插入。在堆总的话就是 一个需要插入的数据。

       从a-->b这段代码,是一个执行插入操作的代码,希尔排序中和直接插入只有细微的差别,当然当i=0时,它们是一样的。不过在堆中虽然不是直接插入,但是思想是不变的,用一个数与另一个数 进行比较,如果小那么不变,大的话就节点互换,向上推进。如果是正宗堆的insert的话,那么更加容易理解,因为insert是直接在最后一个堆节点后再添加一个节点的,然后不断向前推进。

      关于插入的算法就先总结到这,有兴趣的朋友可以互相交流下。。。