算法排序


一、折半插入排序

折半插入排序的算法思想:

算法的基本过程:
(1)计算 0 ~ i-1 的中间点,用 i 索引处的元素与中间值进行比较,如果 i 索引处的元素大,说明要插入的这个元素应该在中间值和刚加入i索引之间,反之,就是在刚开始的位置 到中间值的位置,这样很简单的完成了折半;
(2)在相应的半个范围里面找插入的位置时,不断的用(1)步骤缩小范围,不停的折半,范围依次缩小为 1/2 1/4 1/8 …快速的确定出第 i 个元素要插在什么地方;
(3)确定位置之后,将整个序列后移,并将元素插入到相应位置。
在这里插入图片描述

折半插入排序升序排列

  public static void main(String[] args) {
        int source[] = new int[] { 12, 15, 9, 14, 4, 18, 23, 6 };
        binarySort(source);
    }

    public static void binarySort(int[] source) {
        int i, j;  /*i,j均为循环变量*/
        /*low代表要与Array[i]进行比较的有序区间的第一个元素所在位置。
	      high代表要与Array[i]进行比较的有序区间的最后一个元素所在位置。
	      mid充当比较区间的中点*/
        int high, low, mid;
        int temp; /*temp用来存储当前待排序的数据*/
        for (i = 1; i < source.length; i++) {
            low = 0;// 查找区上界
            high = i - 1;// 查找区下界
            temp = source[i];//将当前待插入记录保存在临时变量中
            while (low <= high) {
                // 找出中间值 向下取整
                // mid = (low + high) / 2;
                mid = (low + high) >> 1;
                //如果待插入记录比中间记录小
                if (temp < source[mid]) {
                    // 插入点在低半区
                    high = mid - 1;
                } else {
                    // 插入点在高半区
                    low = mid + 1;
                }
            }
            //将前面所有大于当前待插入记录的记录后移
            for (j = i - 1; j >= low; j--) {
                source[j + 1] = source[j];
            }
//            for(int j=i;j>low;j--)//把temp放到找到的位       {
//                a[j]=a[j-1];
//            }
            //将待插入记录回填到正确位置.
            source[low] = temp;
            System.out.print("第" + i + "趟排序:");
            System.out.println("soutce==="+ JSON.toJSONString(source));
        }
    }
    
 执行结果:
第1趟排序:[12,15,9,14,4,18,23,6]2趟排序:[9,12,15,14,4,18,23,6]3趟排序:[9,12,14,15,4,18,23,6]4趟排序:[4,9,12,14,15,18,23,6]5趟排序:[4,9,12,14,15,18,23,6]6趟排序:[4,9,12,14,15,18,23,6]7趟排序:[4,6,9,12,14,15,18,23]

折半插入排序降序排列

  public static void main(String[] args) {
        int source[] = new int[] { 12, 15, 9, 14, 4, 18, 23, 6 };
        binarySort(source);
    }

    public static void binarySort(int[] source) {
        int i, j;  /*i,j均为循环变量*/
        /*low代表要与Array[i]进行比较的有序区间的第一个元素所在位置。
	      high代表要与Array[i]进行比较的有序区间的最后一个元素所在位置。
	      mid充当比较区间的中点*/
        int high, low, mid;
        int temp; /*temp用来存储当前待排序的数据*/
        for (i = 1; i < source.length; i++) {
            low = 0;// 查找区上界
            high = i - 1;// 查找区下界
            temp = source[i];//将当前待插入记录保存在临时变量中
            while (low <= high) {
                // 找出中间值 向下取整
                // mid = (low + high) / 2;
                mid = (low + high) >> 1;
                //如果待插入记录比中间记录大
                if (temp >= source[mid]) {
                    // 插入点在低半区
                    high = mid - 1;
                } else {
                    // 插入点在高半区
                    low = mid + 1;
                }
            }
            //将前面所有大于当前待插入记录的记录后移
            for (j = i - 1; j >= low; j--) {
                source[j + 1] = source[j];
            }
//            for(int j=i;j>low;j--)//把temp放到找到的位       {
//                a[j]=a[j-1];
//            }
            //将待插入记录回填到正确位置.
            source[low] = temp;
            System.out.print("第" + i + "趟排序:");
            System.out.println("soutce==="+ JSON.toJSONString(source));
        }
    }

图示:以i=4时为例:

第一步在这里插入图片描述
第二步
在这里插入图片描述
第三步:在这里插入图片描述
第四步:在这里插入图片描述
第五步:
在这里插入图片描述
第六步:在这里插入图片描述
第七步:
在这里插入图片描述

二、希尔排序

算法思想:
希尔排序是将待排序的数组元素 按下标的一定增量分组 ,分成多个子序列,然后对各个子序列进行直接插入排序算法排序;然后依次缩减增量再进行排序,直到增量为1时,进行最后一次直接插入排序,排序结束。
希尔本人给出的步长序列是n/2^k(其中n为数组长度),例如要对下面的数组进行排序,n为16,步长序列是{1, 2, 4, 8}

一种分组排序的方法,以此对数组进行一定的“粗略调整”。
在这里插入图片描述

所谓分组,就是让元素两两一组,同组两个元素之间的跨度,都是数组总长度的一半,也就是跨度为4。在这里插入图片描述
如图所示,元素5和元素9一组,元素8和元素2一组,元素6和元素1一组,元素3和元素7一组,一共4组。

接下来,我们让每组元素进行独立排序,排序方式用直接插入排序即可。由于每一组的元素数量很少,只有两个,所以插入排序的工作量很少。每组排序完成后的数组如下:在这里插入图片描述
这样一来,仅仅经过几次简单的交换,数组整体的有序程度得到了显著提高,使得后续再进行直接插入排序的工作量大大减少。这种做法,可以理解为对原始数组的“粗略调整”。

但是这样还不算完,我们可以进一步缩小分组跨度,重复上述工作。把跨度缩小为原先的一半,也就是跨度为2,重新对元素进行分组:在这里插入图片描述
如图所示,元素5,1,9,6一组,元素2,3,8,7一组,一共两组。
接下来,我们继续让每组元素进行独立排序,排序方式用直接插入排序即可。每组排序完成后的数组如下:在这里插入图片描述
此时,数组的有序程度进一步提高,为后续将要进行的排序铺平了道路。

最后,我们把分组跨度进一步减小,让跨度为1,也就等同于做直接插入排序。经过之前的一系列粗略调整,直接插入排序的工作量减少了很多,排序结果如下:在这里插入图片描述
让我们重新梳理一下分组排序的整个过程:在这里插入图片描述
像这样逐步分组进行粗调,再进行直接插入排序的思想,就是希尔排序

参考样例:
在这里插入图片描述

/**
 * 希尔排序 针对有序序列在插入时采用交换法
 * @param arr
 */
public static void sort(int []arr){
    //增量gap,并逐步缩小增量
    for(int gap=arr.length/2;gap>0;gap/=2){
        //从第gap个元素,逐个对其所在组进行直接插入排序操作
        for(int i=gap;i<arr.length;i++){
            int j = i;
            while(j-gap>=0 && arr[j]<arr[j-gap]){
                //插入排序采用交换法
                swap(arr,j,j-gap);
                j-=gap;
            }
        }
    }
}

参考
https://www.pianshen.com/article/7921137952/
https://www.jianshu.com/p/d730ae586cf3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值