选择,插入,希尔,快速,堆,归并排序六种排序方式的Java 实现和性能对比(付代码)

           最近看书,发现竟然连选择排序的原理都给忘了,囧囧。静下心来把数据结构的五个基础排序算法重新看了,发现以前虽然看过,但是从来没有实现和比较过。正好这个机会用Java 实现并将它们的性能进行比较。里面也有一些疑问:

          既然使用Java ,将每个排序算法看成一个类(有点不妥感觉),不过这样看起来代码组织最直观一下。首先是一个抽象类:

  

package sort;

public abstract class AbstractSort {

	protected static boolean less(Comparable v , Comparable w){
		return v.compareTo(w) < 0 ;
	}
	protected static void exch(Comparable[] a , int i,int j){
		Comparable temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}
	
	protected static void show(Comparable[] a){
		for(int i = 0 ; i < a.length ; i++){
			System.out.print(a[i] + " ");
		}
		System.out.println();
	}
	
	private static boolean isSorted(Comparable[] a){
		
		for(int i = 1 ;i < a.length ; i++)
			if(less(a[i],a[i-1])) return false;
		return true;
	}
}

    然后开始


      1  选择排序(囧)

              选择排序其实思想很简单,就是每次从剩下的里面选择最大或者最小的然后和当前值进行交换。这样的话两重循环可以解决。复杂度是o(n2)

              实现代码如下:

            

package sort;

public class SelectionSort extends AbstractSort {

	public static void sort(Comparable[] a){
		int N = a.length;
		for(int i = 0 ;i < N ;i++){
			int min = i;
			for(int j = i+1 ; j < N ;j++)
				if(less(a[j],a[min])) min = j;
			exch(a,i,min);
		}
	}
}

      2  插入排序

      插入排序原理也是比较简单,保证前面一部分是有序的,然后从第一个无序的和前面的比较如果小于前面的数值就就行交换。理论上复杂度和插入排序一样,可是随即的数组排序比较得出他的速度应该是选择排序的1.2-1.7倍之间。有一个严重的缺点,如果最小的在最后面,那么移动的次数太多

代码如下:

package sort;

public class InsertionSort extends AbstractSort {

	public static void sort(Comparable[] a){
		int N = a.length;
		for(int i= 1 ;i <N; i++){
			for(int j = i; j > 0 && less(a[j],a[j-1]);j--)
				exch(a,j,j-1);
		}
	}
}

     3 希尔排序(名字很古怪)

      希尔排序时针对插入排序的缺点改进的,其实它有三重循环,外面的循环式每次比较的步长,这样的话就可以消除每次只能移动一步的缺点。

package sort;

import java.util.Random;

public class ShellSort extends AbstractSort {

	
	public static void sort(Comparable[] a){
		int N = a.length;
		int step = N/2 ; 
		
		while(step >= 1){
			
			for(int i = step ; i < N ; i++)
				for(int j=i;j>=step && less(a[j],a[j-step]);j-=step)
					exch(a,j,j-step);
			step /= 2;
		}
	}
	
	public static void main(String[] args){
		
		Integer[] a = new Integer[10];
		Random random = new Random();
		for(int i = 0; i < 10; i++)
			a[i] = random.nextInt(100);
		sort(a);
		show(a);
		
	}
}

  4 快速排序思想很清晰,手写一个还是有些问题的

代码如下:


 

package sort;

import java.util.Random;

public class QuickSort extends AbstractSort {

	public static void sort(Comparable[] a){
	   
		quick_sort(a,0,a.length-1);
		
	}

	private static void quick_sort(Comparable[] a, int left, int right) {
		if(left >= right ) return ;
		
		int N = right - left + 1 ; 
		Random  random = new Random();
		int p = random.nextInt(N) + left ;
		
		Comparable temp = a[p] ;
		
		exch(a,right,p);
		int i = left ,
			j = right ;
		    
		while(i < j ){
			while(less(temp,a[j]) && i < j) j-- ;
			if(i < j ) a[i++] = a[j]; 
			
			while(less(a[i],temp) && i < j) i++;
			
			if(i < j )a[j--] = a[i];
		}
		
		a[i] = temp ; 
		
		quick_sort(a,left,i-1);
		quick_sort(a,i+1,right);
	}
	
	
    public static void main(String[] args){
		int N = 10 ; 
		Integer[] a = new Integer[N];
		Random random = new Random();
		for(int i = 0; i < N; i++)
			a[i] = random.nextInt(30);
		sort(a);
		show(a);
		
	}
}


5 堆排序


     我认为最大的问题是实现的时候处理边界的问题,包括了数组和树这种形态结构

代码如下:


package sort;

import java.util.Random;

public class HeapSort extends AbstractSort {

	public static void sort(Comparable[] a){
		buildHeap(a);  // 建立堆
		
		for(int i= a.length - 1 ; i >=1 ; i--){
			exch(a,0,i);
			adjust(a,0,i);  //注意i 的值,开始的时候为length -1
		}
	}
	
	/**
	 *  建立大顶堆
	 * @param a
	 */
	private static void buildHeap(Comparable[] a){
		
		int length = a.length ; 
		for(int i = length/2 -1 ; i >= 0 ;i--)
			adjust(a,i,length);
	}
	/*@name adjust 
	 * @Function: 调整以节点 i 为顶点的堆
	 */
	private static void adjust(Comparable[] a ,int i,int length){ 
		
		int left = 2*i + 1,
			right= 2*i + 2 ;
		if(left >= length && right >= length) return ; 
		int max = i;
		
		if(left < length && less(a[max],a[left]))
			max = left;
		if(right <length && less(a[max],a[right]))
			max = right ;
		if(max!=i){
			exch(a,i,max);
			adjust(a,max,length);
		}
	    
	}
	
	public static void main(String[] args){
		int N = 10 ; 
		Integer[] a = new Integer[N];
		Random random = new Random();
		for(int i = 0; i < N; i++)
			a[i] = random.nextInt(30);
		sort(a);
		show(a);
		
	}
}


6 归并排序

    这里有四种归并排序方法,(自顶向下,自底向上)*(原地归并,飞原地归并)

    

package sort;

import java.util.Random;

public class MerageSort extends AbstractSort {

	private static Comparable[] temp ;
	public static void sort(Comparable[] a){
		temp  =  new Comparable[a.length] ; 
		sort(a,0,a.length - 1);
	}
	/**
	 * 自底向上归并
	 * @param a
	 */
	public static void sortBU(Comparable[] a){
		temp  =  new Comparable[a.length] ; 
		int N = a.length ; 
		for(int step = 1 ;step < N ;step+=step )
			for(int left = 0 ;left < N -step ;left += step +step)
				merage(a,left,left+step-1,Math.min(left+step+step-1, N-1));
	}
	/**
	 * 自顶向下归并排序
	 * @param a
	 * @param left
	 * @param right
	 */
	private static void sort(Comparable[] a ,int left ,int right){
		
		  if(left >= right) return ;
		  int mid = left + (right - left ) / 2;
		  sort(a,left,mid);
		  sort(a,mid+1,right) ; 
		  
		//  merage(a,left,mid,right);
		  merageWithoutTemp(a,left,mid,right);
		  
	}
	/**
	 * 非原地归并排序,需要辅助数组
	 * @param a
	 * @param left
	 * @param mid
	 * @param right
	 */
	private static void merage(Comparable[] a ,int left,int mid,int right){
		
		int i = left , j = mid + 1;
		
		for(int k = left ; k <= right ; k++)
			temp[k] = a[k] ; 
		
		for(int k = left ; k <= right ; k++){
			if(i > mid) a[k] = temp[j++];
			else if(j > right ) a[k] = temp[i++] ;
			else if(less(temp[i],temp[j])) a[k] = temp[i++];
			else a[k] = temp[j++] ;
		}
	}
	
	/**
	 * 原地归并排序,不需要辅助数组,节省空间
	 * @param a
	 * @param left
	 * @param mid
	 * @param right
	 */
	private static void merageWithoutTemp(Comparable[] a ,int left ,int mid , int right ){
		
		int i = left ,j = mid + 1,k =right ;
		int step = 0 ;
		
		while(i < j && j <= k){
			
			while(i < j && less(a[i],a[j])) i++;
			
			while(j <= k && less(a[j],a[i])){j++;step++;}
			
			exchang(a,i,j,step);
			
		}
	}
	private static void exchang(Comparable[] a, int i, int j, int step) {     
		reverse(a,j-step,j-1);
		reverse(a,i,j-step-1);
		reverse(a,i,j-1);
	}

	private static void reverse(Comparable[] a, int begin ,int end){
		while(begin <end)
			exch(a,begin++,end--);
	}
	public static void main(String[] args){
		int N = 10 ; 
		Integer[] a = new Integer[N];
		Random random = new Random();
		for(int i = 0; i < N; i++)
			a[i] = random.nextInt(30);
		sortBU(a);
		show(a);
		
	}
}


    最后是一个用来对各个排序算法进行性能比较的类:

package sort;

import java.util.Random;

import enuminfo.SortEunm;

public class SortCompare {
	

	public static long time(SortEunm sort,Double[] a){
		long startMill = System.currentTimeMillis();
		
		if(sort == SortEunm.INSERTION) InsertionSort.sort(a);
		else if(sort == SortEunm.SELECTION) SelectionSort.sort(a);
		else if(sort == SortEunm.SHELL) ShellSort.sort(a);
		else if(sort == SortEunm.QUICK) QuickSort.sort(a);
		else if(sort == SortEunm.HEAP) HeapSort.sort(a);
		long endMill = System.currentTimeMillis();
		return endMill - startMill ;
	}
	
	public static long timeRandomInput(SortEunm sort,int N,int T){
		long total = 0;
		
		Double[] a = new Double[N];
		
		for(int t = 0 ; t < T ; t++){
			Random r = new Random();
			for(int i = 0 ; i < N ;i++)
				a[i] = r.nextDouble(); 
			total += time(sort,a);
		}
		
		return total;
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		int N = 1000;
		int T = 1000;
		
		long selectionTimes = timeRandomInput(SortEunm.SELECTION,N,T);
		long insertionTimes = timeRandomInput(SortEunm.INSERTION,N,T);
		long shellTimes = timeRandomInput(SortEunm.SHELL,N,T);
		long quickTimes = timeRandomInput(SortEunm.QUICK,N,T);
		long heapTimes = timeRandomInput(SortEunm.HEAP,N,T);
		
		System.out.println("For "+ N +" random double and "+ T +" times :");
		System.out.println("InsertionSort's time :" + insertionTimes);
		System.out.println("SelectionSor's time :" + selectionTimes);
		System.out.println("Shell's time : " + shellTimes);
		System.out.println("quick's time :" + quickTimes);
		System.out.println("heap's time   :" + heapTimes);
		System.out.println("insertionsTimes/SelectionsTimes = " + 1.0 * insertionTimes/selectionTimes);
		System.out.println("shellTimes/insertionTimes = " + 1.0*shellTimes/insertionTimes);
		
	}

}


以及一个枚举 :


  

package enuminfo;

public enum SortEunm {

	SELECTION,
	INSERTION,
	SHELL,
	QUICK,
	HEAP;
}


希尔排序的速度大约是选择排序的 7 倍左右:

运行结果如下:


代码见:   https://github.com/Turtledove/EnHanceExercises/tree/master/EnHanceExercises/src 待续

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值