Java 排序实现

  最近在看JAVA的一些排序算法,和大家分享一下,感觉非常有帮助~~为了简化,这里直接采用数组进行排序,没有引入比较策略。

为了便于测试,编写了一个生产数组的方法,如下:

/**
 * 为排序生产测试数据
 * @author Administrator
 *
 */
public class NumberFactory {
	
	/**
	 * 成产1个含有n个数的数组,每个数的大小在1-n之间
	 * @param n 数据的个数
	 * @return 生产的数组
	 */
	public static int[] buildNumber(int n){
		int[] num = new int[n];
		Random random = new Random();
		for(int i = 0;i < num.length;i++){
			num[i] = random.nextInt(n);
		}
		return num;
		
	}

}

1 插入排序

1.1基本思路

     从前往后进行循环(由n-1趟循环完成),当到循环到第p个数时,该算法保证前面的p-1个数都是有序的。

1.2复杂度

插入排序的平均复杂度为O( n2)。在下面的方法中,如果待排数组是以排序的,那么复杂度为O(n)。

1.3实现

import java.util.Arrays;
/**
 * 插入排序
 * @author Administrator
 *
 */
public class InsertSequenceTest {
	/**
	 * 插入排序
	 * @param array
	 */
	public static void insertSequence(int array[]){
		int j;
		for(int i=0;i0&&p

2希尔排序

2.1基本思路

该方法引入一个增量序列h1,h2,h3...,该增量是递减的,算法保证每轮循环中每隔增量h的数都是已排序的,如当增量为3时数组{4, 2, 3,6, 8, 7,10, 9, 8},当增量为1时,排序完成。

2.2复杂度

该算法有着亚二次时间界。使用希尔排序的对坏情形的复杂度为O( n2),但是当增量h选择合理时最坏情形可达到O( n 3/2)。

2.3实现

import java.util.Arrays;

/**
 * 希尔排序
 * @author Administrator
 *
 */
public class ShellsortSquenceTest {

	/**
	 * 希尔排序
	 * @param array 代排序数组
	 */
	public static void shellsort(int array[]){
		for(int shell = array.length/2;shell>0;shell/=2){//递减的增量
			int j;
			for(int i = shell;i= 0&&o < array[j-shell];j -= shell){
					array[j] = array[j-shell];
				}
				array[j] = o;
			}
		}
	}

}

3堆排序

3.1基本思路

         堆是一个被完全填满的二叉树,如果是大顶堆则每个父亲节点的值不小于其所有孩子的值,小顶堆则相反。在堆中很容易找到她的左孩子(2n+1)。堆排序首先先建立一个堆,然后让其根节点与最后一个叶子节点交换,此时堆的结构被破坏(根节点被替换),然后将根节点下滤到适合她的位置,循环直到剩下最后一个根节点(值得注意的是,在下滤的过程中由于不能肯定节点是否有右孩子,所以应做判断)。

3.2复杂度

构建堆需要O(n)的时间,每个元素下滤需要O(logn)的时间,n个元素的时间为O(nlogn),所以复杂度为O(n)+O(nlogn)即O(nlogn)。

3.3实现

import java.util.Arrays;
public class HeapSequenceTest {

	/**
	 * 堆排序
	 * @param a
	 */
	public static void heapSort(int[] a){
		for(int i = a.length/2; i >= 0; i--) //先建立堆
			percolatedown(a,i,a.length);
		for(int i = a.length-1; i >= 0; i--){//将头尾互换,建立堆
			changeNum(a, 0, i);
			percolatedown(a,0,i);
		}
	}
	/**
	 * 建立堆主方法           
	 * @param a 
	 * @param begin 开始位置
	 * @param len 需要的总长度
	 */
	private static void percolatedown(int[] a, int begin, int len) {
		int child;    //与父亲交换位置的孩子
		int temp = a[begin];  //用于存放变量
		int j = 1;
		for(; leftchild(begin) < len; begin = child){
			child = leftchild(begin);
			//如果存在右孩子,选择一个最小的
			if(child+1 < len&& a[child] < a[child+1])  
				child++;
			if(temp < a[child]){
				a[begin] = a[child];
			}
			else
				break;
			j++;
		}
		a[begin] = temp;
	}
	
	/**
	 * 返回左孩子的下标
	 * @param begin
	 * @return 
	 */
	private static int leftchild(int begin) {
		return 2*begin+1;
	}

	/**
	 * 交换次序,该方法用于交换数组内两个下标的数字
	 * @param a 待交换的数组
	 * @param left 被交换的下标1
	 * @param center 被交换的下标2
	 */
	private static void changeNum(int[] a, int arg1, int arg2) {
		int tem = a[arg1];
		a[arg1] = a[arg2];
		a[arg2] = tem;
	}
	public static void main(String[] args) {
		int[] a = NumberFactory.buildNumber(19);
		System.out.println("***********堆排序前**************");
		System.out.println(Arrays.toString(a));
		System.out.println("***********堆排序后**************");
		HeapSequenceTest.heapSort(a);
		System.out.println(Arrays.toString(a));
	}
}

4归并排序

4.1基本思路

归并排序是合并已经排序的表,基本思路如下(递归分治思想)
待排序列 {56,12,34,1,7,65,9 }
第一步结果 {[12,56 ][1,34 ][7,65 ][9 ]}
第二步结果 {[1,12,34,56 ][7,9,65 ]}
第三部结果 {[1,7,9,12,34,56,65 ]}
该方法是经典的分治策略,她将问题分成一些小的问题然后递归求解。

4.2复杂度

归并排序的复杂度是O(nlogn),但是有个明显的缺点是该方法需要拷贝的线性附加内存,所以内存开销会比较大,但是她的明显优点是有着很少的比较次数。

4.3实现

/**
 * 归并排序
 * @author Administrator
 *
 */
public class MergeSequenceTest {
	
	/**
	 * 引出归并排序
	 * @param a 待排序数组
	 */
	public static void mergeSort(int[] a){
		int[] temp = new int[a.length];
		mergeSort(a,temp,0,a.length-1);
	}
	
	/**
	 * 递归调用归并
	 * @param a 待排序数组
	 * @param temp 被拷贝的数组
	 * @param left 待排数组起始
	 * @param right 待排数组结尾
	 */
	private static void mergeSort(int[] a, int[] temp, int left, int right) {
		if(left


5快速排序

5.1基本思路

快速排序也是采用分治的思想,在快速排序中首先是找到一个枢纽元素,一轮排序后比枢纽小的放在枢纽前面,比枢纽大的放在枢纽后面。
待排序列 {56,12,34,1,7,65,9}
选取枢纽34后(在下面的算法实现中选取枢纽采用了(首+中+尾)三点选取中值所以结果与下方有所不同,但是思想没变)
第一步结果 {9,12,1,7, 34 ,65,56}(9与56互换。。。)
第二步结果 {9,1,7,12,34,56,65}(下划线为第二轮枢纽)
第三部结果 {1,7,9,12,34,56,65}

5.2复杂度

快速排序的最坏运行时间为O( n 2),但是如果枢纽选择合理很少会出现最坏情况,她的平均时间为O(nlogn)。

5.3实现

在下面的方法中,枢纽采用三个点选取中值的方法。另外考虑到存在相等元素的情况,为了保证分治的平衡(如果全部相等则会出现最坏情况,即分治不均匀)所以遇到相等的也会进行交换。
package com.example.sequence;

import java.util.Arrays;

public class QuickSequenceTest {
	
	/**
	 * 快速排序入口
	 * @param a
	 */
	public static void quickSort(int[] a){
		quickSort(a,0,a.length-1);
	}
	
	/**
	 * 快速排序主方法
	 * @param a
	 * @param left
	 * @param right
	 */
	private static void quickSort(int[] a, int left, int right) {
		if(left+1 < right){
			//查找枢纽中值
			int flag = findFlag(a,left,right);
			int i = left, j = right-1;
			for(;;){
				while(a[++i] < flag){}    //此行可看出快速排序的优势。
				while(a[--j] > flag){}    //相等也进行交换,防止递归不均匀
				if(i


你可能感兴趣的:(java,插入排序,希尔排序,堆排序,归并排序,快速排序)