希尔排序算法

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,希尔排序是直接插入排序的升级版本,也称为缩小增量排序,同时该算法是冲破O(n^2)的第一批算法之一。

直接插入排序算法的思想:
把n个待排序的元素看成一个有序表,一个无序表,开始的时候,有序表只包含n-1个元素,排序过程中每次从无序表中取第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将他插入到有序表的合适位置

希尔排序的基本思想是:
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

希尔排序的排序效率和选择步长序列有直接关系,从length逐步减半,这还不算最快的希尔,还有其他别的步长序列会更快,这里就不再说明,具体可以去各大网站查找

由于直接插入排序在元素基本有序的情况下效率很高,因此希尔排序在时间效率上比前两种方法有较大提高。

下面我写了交换式希尔排序和移位式希尔排序
交换式希尔排序内部使用了 冒泡排序
移位式希尔排序内部使用了 直接插入排序

在这里插入图片描述

public class ShellSort{
	public static void main(String[] args){
		int[] arr = {1, 21, 12, 2, 32, 41, 2, 3, 231, 5, 87};
		shellSort(arr);
	}
	//交换法的希尔排序
	//先推导3轮 最后整合最终的表达式
	public static void shellSort(int[] arr){
		int temp = 0;
		//希尔排序第一轮排序
		//因为第一轮排序是将10个数据分成5组
		for(int i = 5; i < arr.length; i++){
			//下面是在分好的数组中进行直接插入排序
			for(int j = i - 5;j >= 0;j -= 5){
				if(arr[j]>arr[j + 5]){
					temp = arr[j];
					arr[j] = arr[j + 5];
					arr[j + 5] = arr[j];
				}
			}
		}
		//希尔排序第二轮排序
		//因为第二轮排序是将10个数据分成5 / 2组 = 2组
		for(int i = 2; i < arr.length; i++){
			for(int j = i -2;j >= 0; j-=2){
				if(arr[j] > arr[j+2]){
					temp = arr[j];
					arr[j] = arr[j + 2];
					arr[j + 2] = temp;
				}
			}
		}
		//希尔排序第三轮排序
		for(int i = 1;i < arr.length;i++){
			for(int j = i - 1;j >= 0;j-=1){
				if(arr[j] > arr[j + 1]){
					temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
		}
	}
}

推出最终的交换式希尔排序算法

	//以此类推
		int temp = 0;
		int count = 0;
		boolean flag = false;
		for(int gap = arr.length/2;gap > 0;gap /= 2){
			for(int i = gap;i < arr.length;i++){
				for(int j = i - gap;j >= 0;j -=gap){
					if(arr[j] > arr[j + gap]){
						flag = true;
						temp = arr[j];
						arr[j] = arr[j + gap];
						arr[j + gap] = temp;
					}
					//这里对插入算法进行优化
					//当判定第一个插入比较的时候,如果没有发成交换
					//则说明都是有序的 不需要再排序了
					if(!flag){
						break;
					}else{
						flag = false;
					}
				}
			}
		}

但我们发现交换式希尔排序的效率并不高
于是我们决定使用移位式希尔排序(内部利用了插入排序)

 int count = 0;
        //增量gap 并逐步的缩小增量
        for(int gap = arr.length/2;gap>0;gap/=2){
            //从第gap个元素,逐个对其所在组进行直接插入排序
            //其实就是把交换法中的冒泡排序变成了直接插入排序
            for(int i = gap;i<arr.length;i++){
                int j = i;//待插入位置
                int temp = arr[j];
                //如果arr[j] >= arr[j - gap]  本轮就没必要进行插入排序
				//比如 {1, 2, 4} 2 < 4 又2和1一定是排好的 所以本轮不需要排序
                if(arr[j]<arr[j-gap]) {
                    while(j - gap >= 0 && temp < arr[j-gap]) {
                        //移动
                        arr[j] = arr[j - gap];//发现待插入的比插入的小 就把插入的值后移gap位
                        j -= gap;//插入坐标前移gap位
                    }
                    //退出while循环表明 已经找到插入位置
					//即temp >= arr[j - gap]
					//将temp放在j位置上即可
                    arr[j] = temp;
                }
            }
            count++;
        }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值