排序算法之希尔排序(Shell Sort)

希尔排序(Shell Sort)


描述
  1. 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
  2. 按增量序列个数 k,对序列进行 k 趟排序;
  3. 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
案例

当前有一个数组 { 5,6,1,3,8,4,6,9,0,2 } ,用 希尔排序 对其进行 升序 排序

代码

代码思路:

  1. 首先定义一个包含1的跨度集合,例如{6,4,2,1}
  2. 循环跨度,将原本的数列通过跨度划分成不同的子序列(关于通过跨度将原数列划分成多个子数列,可以看一下代码中的注释
  3. 将子序列通过插入排序进行排序
package com.suanfa.sort;

import java.util.Arrays;

public class ShellSort {

	public static void main(String[] args) {
		
		
		int[] a = {5,6,1,3,8,4,6,9,0,2};
		
		//需要先定义跨度t1,t2,t3,....,tk。tk=1
		//跨度可以自己任意定义,只用保证tk=1即可、
		int[] g = {6,4,2,1};
		System.out.println("希尔排序跨度定义:"+Arrays.toString(g));

		
		System.out.println("起始选择排序结果:"+Arrays.toString(a));

		int totalChangeNum = 0;//此处对元素大小排序触发位置互换的次数做了统计
		
		//循环跨度
		int n = 0;
		while(n < g.length){
			//根据跨度对数列{5,6,1,3,8,4,6,9,0,2}进行分组
			//下面按跨度划分子序列都只针对于{5,6,1,3,8,4,6,9,0,2}做的划分,与代码执行过程中的不一致
			//当跨度为6时,数列被分为{5,6},{6,9},{1,0},{3,2},{8},{4},{6}
			//当跨度为4时,数列被分为{5,8,0},{6,4,2},{1,6},{3,9}
			//当跨度为2时,数列被分为{5,1,8,6,0},{6,3,4,9,2}
			//当跨度为1时,数列被分为{5,6,1,3,8,4,6,9,0,2}
			//当数列通过跨度分为多个子序列时,子序列通过插入排序进行排序
			//最终在跨度为1时的排序,会将序列排列成最终要的结果
			System.out.println("当前处理跨度为:"+g[n]);
			
			for(int i=g[n];i<a.length;i++){
				//将同子序列的进行插入排序
				for(int j=i;j>=0 && (j-g[n])>=0;j-=g[n]){
					if(a[j-g[n]] > a[j]){
						int temp = a[j];
						a[j] = a[j-g[n]];
						a[j-g[n]] = temp;
						totalChangeNum++;
						System.out.println("位置互换:"+j+" <=> "+(j-g[n]));

					}
				}
				System.out.println("跨度["+g[n]+"]-开始处理值下标位置["+i+"]-第"+(i+1-g[n])+"次循环结果:"+Arrays.toString(a));
			}
			n++;//进行下一个跨度的插入排序
		}
		System.out.println("哈希排序数列总共触发了 "+totalChangeNum+" 位置互换");
	}
}


控制台日志输出
希尔排序跨度定义:[6, 4, 2, 1]
起始选择排序结果:[5, 6, 1, 3, 8, 4, 6, 9, 0, 2]
当前处理跨度为:6
跨度[6]-开始处理值下标位置[6]-第1次循环结果:[5, 6, 1, 3, 8, 4, 6, 9, 0, 2]
跨度[6]-开始处理值下标位置[7]-第2次循环结果:[5, 6, 1, 3, 8, 4, 6, 9, 0, 2]
位置互换:8 <=> 2
跨度[6]-开始处理值下标位置[8]-第3次循环结果:[5, 6, 0, 3, 8, 4, 6, 9, 1, 2]
位置互换:9 <=> 3
跨度[6]-开始处理值下标位置[9]-第4次循环结果:[5, 6, 0, 2, 8, 4, 6, 9, 1, 3]
当前处理跨度为:4
跨度[4]-开始处理值下标位置[4]-第1次循环结果:[5, 6, 0, 2, 8, 4, 6, 9, 1, 3]
位置互换:5 <=> 1
跨度[4]-开始处理值下标位置[5]-第2次循环结果:[5, 4, 0, 2, 8, 6, 6, 9, 1, 3]
跨度[4]-开始处理值下标位置[6]-第3次循环结果:[5, 4, 0, 2, 8, 6, 6, 9, 1, 3]
跨度[4]-开始处理值下标位置[7]-第4次循环结果:[5, 4, 0, 2, 8, 6, 6, 9, 1, 3]
位置互换:8 <=> 4
位置互换:4 <=> 0
跨度[4]-开始处理值下标位置[8]-第5次循环结果:[1, 4, 0, 2, 5, 6, 6, 9, 8, 3]
位置互换:9 <=> 5
位置互换:5 <=> 1
跨度[4]-开始处理值下标位置[9]-第6次循环结果:[1, 3, 0, 2, 5, 4, 6, 9, 8, 6]
当前处理跨度为:2
位置互换:2 <=> 0
跨度[2]-开始处理值下标位置[2]-第1次循环结果:[0, 3, 1, 2, 5, 4, 6, 9, 8, 6]
位置互换:3 <=> 1
跨度[2]-开始处理值下标位置[3]-第2次循环结果:[0, 2, 1, 3, 5, 4, 6, 9, 8, 6]
跨度[2]-开始处理值下标位置[4]-第3次循环结果:[0, 2, 1, 3, 5, 4, 6, 9, 8, 6]
跨度[2]-开始处理值下标位置[5]-第4次循环结果:[0, 2, 1, 3, 5, 4, 6, 9, 8, 6]
跨度[2]-开始处理值下标位置[6]-第5次循环结果:[0, 2, 1, 3, 5, 4, 6, 9, 8, 6]
跨度[2]-开始处理值下标位置[7]-第6次循环结果:[0, 2, 1, 3, 5, 4, 6, 9, 8, 6]
跨度[2]-开始处理值下标位置[8]-第7次循环结果:[0, 2, 1, 3, 5, 4, 6, 9, 8, 6]
位置互换:9 <=> 7
跨度[2]-开始处理值下标位置[9]-第8次循环结果:[0, 2, 1, 3, 5, 4, 6, 6, 8, 9]
当前处理跨度为:1
跨度[1]-开始处理值下标位置[1]-第1次循环结果:[0, 2, 1, 3, 5, 4, 6, 6, 8, 9]
位置互换:2 <=> 1
跨度[1]-开始处理值下标位置[2]-第2次循环结果:[0, 1, 2, 3, 5, 4, 6, 6, 8, 9]
跨度[1]-开始处理值下标位置[3]-第3次循环结果:[0, 1, 2, 3, 5, 4, 6, 6, 8, 9]
跨度[1]-开始处理值下标位置[4]-第4次循环结果:[0, 1, 2, 3, 5, 4, 6, 6, 8, 9]
位置互换:5 <=> 4
跨度[1]-开始处理值下标位置[5]-第5次循环结果:[0, 1, 2, 3, 4, 5, 6, 6, 8, 9]
跨度[1]-开始处理值下标位置[6]-第6次循环结果:[0, 1, 2, 3, 4, 5, 6, 6, 8, 9]
跨度[1]-开始处理值下标位置[7]-第7次循环结果:[0, 1, 2, 3, 4, 5, 6, 6, 8, 9]
跨度[1]-开始处理值下标位置[8]-第8次循环结果:[0, 1, 2, 3, 4, 5, 6, 6, 8, 9]
跨度[1]-开始处理值下标位置[9]-第9次循环结果:[0, 1, 2, 3, 4, 5, 6, 6, 8, 9]
哈希排序数列总共触发了 12 位置互换

注:
我特地用插入排序算法加日志跑了一遍,发现插入排序总共触发了23次位置互换,比哈希算法多了好多,这时候去了解了一下哈希排序的思想理念。

对于插入排序这个O(N2)级别的算法来说,越是有序的序列,它所需要的时间越少,甚至在某些情况下可以逼近O(N)

而希尔排序就是将原序列进行了一些整理,将其变得有序一些

希尔排序是在插入排序的基础上进行的一中改进的算法,希尔排序是将一个原序列分成几个子序列,对于每个子序列来所都进行一次插入排序,

而依据不同的子序列划分大小,最后子序列为1时,进行的那一次插入排序跟原来的插入排序就是一模一样的了,只不过现在的队列比原来的要有序的多。

前面多次跨度不为一的插入排序就是为了在最后一次跨度为1时的插入排序要处理的数列变得更加有序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值