插入、选择、冒泡三者比较以及希尔算法

在这三个基础算法中,都是基于比较进行的排序,时间复杂度都为O(n²),并且都是原地排序,也都是稳定的算法。

插入排序的目的是建立一个有序的数组随后进行插入。在内层循环中可以提前结束比较。在数据量小或者接近有序的情况下,比较适合。

冒泡排序是当前节点和相邻节点进行比较,与插入排序不同的是,冒泡排序建立的是一个大局上的有序数组。在冒泡的过程是,单个元素本身是不会根据数组是否有序进行的,也就说有序无序它都会这样进行比较。是一个比较稳健的算法。

然后就是选择排序,特点是建立小范围的有序数组,和插入的不同是,选择排序是通过全局最小来建立有序,而插入是在小范围有序中维护有序。

一般开发中,插入排序会使用的多一点。从代码实现上来看,冒泡排序的数据交换要比插入排序的数据移动要复杂,冒泡排序需要 3个赋值操作,而插入排序只需要1个,所以在对相同数组进行排序时,冒泡排序的运行时间理 论上要长于插入排序。

这样看来如果能规避掉插入排序中最差的情况,就可以提升整个插入算法的时间效率。

 

Shell排序:希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

简单插入排序很循规蹈矩,不管数组分布是怎么样的,依然一步一步的对元素进行比较,移动,插入,比如[5,4,3,2,1,0]这种倒序序列,数组末端的0要回到首位置很是费劲,比较和移动元素均需n-1次。而希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,然后分组进行插入排序,随后逐步缩小增量,继续按组进行插入排序操作,直至增量为1。希尔排序通过这种策略使得整个数组在初始阶段达到从宏观上看基本有序,小的基本在前,大的基本在后。然后缩小增量,到增量为1时,其实多数情况下只需微调即可,不会涉及过多的数据移动。

我们来看下希尔排序的基本步骤,在此我们选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2...1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。

如果步长为1了那么就变成了插入排序。注意加粗的三个地方就行了,这个算法也不是特别的点。可能刚刚看这个排序的时候,在想这和插入排序有什么区别。个人认为区别就是插入是对每一个数据进行遍历是个体的思想,Shell是总体的思想。先让整体慢慢的趋于有序。特点就是有序,复杂度为O(nlog步长n)

public void shellSort(int[] arr ){
        //希尔排序  升序
        for (int d = arr.length / 2;d>0;d /= 2){ //d:增量  7   3   1
            for (int i = d; i < arr.length; i++){
                //i:代表即将插入的元素角标,作为每一组比较数据的最后一个元素角标
                //j:代表与i同一组的数组元素角标
                for (int j = i-d; j>=0; j-=d){ //在此处-d 为了避免下面数组角标越界
                    if (arr[j] > arr[j + d]) {// j+d 代表即将插入的元素所在的角标
                        //符合条件,插入元素(交换位置)
                        int temp = arr[j];
                        arr[j] = arr[j + d];
                        arr[j + d] = temp;
                    }
                }
            }
        }
    }

  

posted @ 2020-12-10 11:25  smartcat994  阅读(883)  评论(0编辑  收藏  举报