zoukankan      html  css  js  c++  java
  • 用分解的方式学算法003——希尔排序

    希尔排序是插入排序的一个变种。对于大规模乱序数组插入排序很慢,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一端。希尔排序为了加快速度简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

    先看一段希尔排序的实现的代码:

    	public static void ShellSort1() {
    		int[] a = { 49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 1 };
    		// 希尔排序
    		int d = a.length;
    		while (true) {
    			d = d / 2;
    			for (int x = 0; x < d; x++) {
    				for (int i = x + d; i < a.length; i = i + d) {
    					int temp = a[i];
    					int j;
    					for (j = i - d; j >= 0 && a[j] > temp; j = j - d) {
    						a[j + d] = a[j];
    					}
    					a[j + d] = temp;
    				}
    			}
    			if (d == 1) {
    				break;
    			}
    		}
    	}
    

     这段代码有三层循环,下面我们将其进行分解。

    第一步,先是一个基本的插入排序的算法:

    	public static void InserSort1(int[] a){
    		for(int i=1;i<a.length;i=i+1){
    			int temp = a[i];
    			int j=i-1;
    			while(j>=0&&temp<a[j]){
    				a[j+1]=a[j];
    				j=j-1;
    			}
    			a[j+1]=temp;
    		}
    	}
    

     将其进行改进,改为可以指定步进长度,也就是把原来所有出现的“1”都改为“d”。

    这样就将默认的步进长度,由“依次”改为人为指定长度d。

    	public static void InserSort1(int[] a,int d){
    		for(int i=d;i<a.length;i=i+d){
    			int temp = a[i];
    			int j=i-d;
    			while(j>=0&&temp<a[j]){
    				a[j+d]=a[j];
    				j=j-d;
    			}
    			a[j+d]=temp;
    		}
    	}
    

     第二步,确定步进长度d,采用缩减式。每次缩减为原长度的某个比例。可固定为一半,即divid=2。

    	public static int MakeSetpLength(int d,int divid){
    		d=d/divid;
    		return d;
    	}
    

     第三步,组合。由大到小的采用一系列步进长度d,当d==1时,再进行最后一次插入排序,然后结束。

    	public static void ShellSort(int[] a){
    		int d=a.length;
    		while(true){
    			int divid=2;//可以改为变化的缩进,如2,3,5,8...这样的缩进方式。
                          //这种方式需要记录原长度a.length d=MakeSetpLength(d,divid); InserSort1(a,d); if(d==1){ break; } } }

     完整代码如下:

    package asen.yang;
    
    public class shellSort {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    
    		int[] a = { 49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 1 };
    		ShellSort(a);
    		for (int i = 0; i < a.length; i++) {
    			System.out.print(a[i] + " ");
    		}
    	}
    
    	public static void ShellSort0(Comparable[] a) {
    		int N = a.length;
    		int h = 1;
    		while (h < N / 3) {
    			h = 3 * h + 1;
    		}
    		while (h >= 1) {
    			for (int i = h; i < N; i++) {
    				for (int j = i; j >= h && a[j].compareTo(a[j - h]) < 0; j = j - h) {
    					Comparable temp = a[j];
    					a[j] = a[j - h];
    					a[j - h] = temp;
    				}
    			}
    			h = h / 3;
    		}
    	}
    	
    	public static void InserSort1(int[] a){
    		for(int i=1;i<a.length;i++){
    			int temp = a[i];
    			int j=i-1;
    			while(j>=0&&temp<a[j]){
    				a[j+1]=a[j];
    				j--;
    			}
    			a[j+1]=temp;
    		}
    	}
    	
    	public static void InserSort1(int[] a,int d){
    		for(int i=d;i<a.length;i=i+d){
    			int temp = a[i];
    			int j=i-d;
    			while(j>=0&&temp<a[j]){
    				a[j+d]=a[j];
    				j=j-d;
    			}
    			a[j+d]=temp;
    		}
    	}
    	
    	public static int MakeSetpLength(int d,int divid){
    		d=d/divid;
    		return d;
    	}
    	
    	public static void ShellSort(int[] a){
    		int d=a.length;
    		while(true){
    			int divid=2;//可以改为变化的缩进,如2,3,5,8...这样的缩进方式。这种方式需要记录原长度a.length
    			d=MakeSetpLength(d,divid);
    			InserSort1(a,d);
    			
    			if(d==1){
    				break;
    			}
    		}
    	}
    
    	public static void ShellSort1() {
    		int[] a = { 49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 1 };
    		System.out.println("排序之前:");
    		for (int i = 0; i < a.length; i++) {
    			System.out.print(a[i] + " ");
    		}
    		// 希尔排序
    		int d = a.length;
    		while (true) {
    			d = d / 2;
    			for (int x = 0; x < d; x++) {
    				for (int i = x + d; i < a.length; i = i + d) {
    					int temp = a[i];
    					int j;
    					for (j = i - d; j >= 0 && a[j] > temp; j = j - d) {
    						a[j + d] = a[j];
    					}
    					a[j + d] = temp;
    				}
    			}
    			if (d == 1) {
    				break;
    			}
    		}
    		System.out.println();
    		System.out.println("排序之后:");
    		for (int i = 0; i < a.length; i++) {
    			System.out.print(a[i] + " ");
    		}
    	}
    
    }
    

     在上面的代码中,有一个ShellSort0的实现,这种方式在某些教材中出现,但是不好理解。有需要的朋友可以参考一下。

  • 相关阅读:
    Java实现 LeetCode 382 链表随机节点
    Java实现 LeetCode 382 链表随机节点
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素
    Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
    Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
    Linux下的iwpriv(iwlist、iwconfig)的简单应用
    OCX控件的注册卸载,以及判断是否注册
    .OCX、.dll文件注册命令Regsvr32的使用
  • 原文地址:https://www.cnblogs.com/asenyang/p/8810978.html
Copyright © 2011-2022 走看看