八种常见排序算法:插入、冒泡、选择、希尔、归并、快排、堆排序、基数排序

package com.algorithm;

import java.util.Random;

/**
 * 八种常见排序算法:插入、冒泡、选择、希尔、归并、快排、堆排序、基数排序
 * @author Wennian
 *
 */

public class Sort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 构建初始化乱序数组,采用随机数的方式,生成整数(正数、0、负数)
		int N = 100;
		int[] arr = new int[N];
		for(int i=0;i<N;i++){
			// 随机生成0-N-1的数,其中1/10的数为负数
			arr[i] = new Random().nextInt(N) - N/10;
		}
		Sort sort = new Sort();
		//sort.BubbleSort(arr);
		//sort.InserSort(arr);
		//sort.SelectSort(arr);
		//sort.SheelSort(arr);
		//sort.QuickSort(arr);
		//sort.mergeSort(arr);
		sort.heapSort(arr);
		for(int i=0;i<N;i++){
			System.out.print(arr[i]+" ");
			if(i%10 == 0 && i>0){
				System.out.println();
			}
		}
		
	}
	
	/**
	 * 冒泡排序:一组数,每次把最大的数往后沉
	 * 时间复杂度:o(n^2) 空间复杂度:o(1)
	 * 稳定
	 */
	void BubbleSort(int[] arr){
		int len = arr.length;
		int end = len-1; // 初始时,结束位置为数组末尾
		int start = 0;   // 每次从第一个元素开始往后遍历
		
		// 一共需要len趟才能排序完成
		for(int i=0;i<len;i++){
			start = 0;
			while(start < end){
				if(arr[start]>arr[start+1]){
					arr[start] ^= arr[start+1];
					arr[start+1] ^= arr[start];
					arr[start] ^= arr[start+1];
				}
				start++;
			}
			end--; //每趟排序之后,待排数组长度减1
		}
	}
	
	/**
	 * 插入排序:认为前面的数组已经有序,每次向原来的数组中插入一个数
	 * 时间复杂度o(n^2) 空间复杂度o(1)
	 * 稳定
	 * @param arr
	 */
	void InserSort(int[] arr){
		int len = arr.length;
		int end = 0; // 已经排序好的数组
		int start = end+1; // 下一个要插入的元素
		while(start<=len-1){
			for(int i = end;i>=0;i--){
				if(arr[i+1]<arr[i]){
					arr[i+1] ^= arr[i];
					arr[i] ^= arr[i+1];
					arr[i+1] ^= arr[i];
				}else{
					break;
				}
			}
			end = start;
			start++;
		}
	}
	
	/**
	 * 选择排序:有序区和无序区,有序区的元素小于无序区,每次选择无需去的最小元素放在有序区后面
	 * 时间复杂度o(n^2) 空间复杂度o(1)
	 * 稳定
	 */
	void SelectSort(int[] arr){
		int len = arr.length;
		int start = 0; // 无序区的第一个元素,认为他是最小值
		while(start < len){			
			for(int i=start+1;i<len;i++){
				if(arr[start]>arr[i]){
					arr[start] ^= arr[i];
					arr[i] ^= arr[start];
					arr[start] ^= arr[i];
				}
			}
			start++;
		}
	}
	
	/**
	 * 希尔排序:缩小增量排序,每次缩小增量gap,间隔gap的数为一个子序列,
	 * 依次缩小增量,直到gap=1,对每个子序列采用直接选择排序
	 * 时间复杂度o(nlogn)~o(n^2) 空间复杂度 o(1)
	 * 不稳定
	 */
	void SheelSort(int[] arr){
		int len = arr.length;
		
		// gap选择为奇数,gap的选择直接影响排序的效率
		// 若选择偶数,gap=4会重复gap=8的排序比较,时间浪费
		for(int gap=len/2+1;gap>0;gap/=2){
			//对子序列进行直接选择排序,一共有gap个子序列
			for(int subarr=0;subarr<gap;subarr++){
				int start = subarr;
				// 直接选择排序
				while(start<len){
					for(int i=start+gap;i<len;i+=gap){
						if(arr[start]>arr[i]){
							arr[start] ^= arr[i];
							arr[i] ^= arr[start];
							arr[start] ^= arr[i];
						}
					}
					start +=gap;
				}
				
			}
			
		}
	}
	
	/**
	 * 快序排序:每次找到一个分割值,满足:左边<=分割值<=右边,重复此过程直到有序
	 * 时间复杂度o(nlogn) 空间复杂度o(1)
	 * 不稳定
	 * @param arr
	 */
	void QuickSort(int[] arr){
		int len =arr.length;
		int left = 0 ;
		int right = len-1;
		quickSort(arr,left,right);
	}
	void quickSort(int[] arr ,int left,int right){
		if(left < right){
			int split = arr[left];
			int index1 = left, index2 = right;
			while(index1<index2){
				while(arr[index2]>=split && index1<index2){
					index2--;
				}
				if(index1<index2)
					arr[index1++] = arr[index2];
				
				while(arr[index1]<=split && index1<index2){
					index1++;
				}
				if(index1<index2)
					arr[index2--] = arr[index1];
			}
			arr[index1] = split;
			
			// 递归调用
			quickSort(arr,left,index1);
			quickSort(arr,index1+1,right);
		}
		
	}
	
	
	/**
	 * 归并排序:将数组分为子数组,认为每一个子数组已经有序,对两个有序数组进行归并
	 * 时间复杂度o(nlogn) 空间复杂度o(n)
	 * 稳定
	 */	
	void mergeSort(int[] arr){
		int len = arr.length;
		if(len<=0)
			return;
		divideArray(arr,0,len-1);
	}
	void divideArray(int[] arr,int left,int right){
		if(left < right){
			int mid = left + (right - left)/2;
			// 分解
			divideArray(arr,left,mid);
			divideArray(arr,mid+1,right);
			// 合并
			mergeArray(arr,left,mid,right);
		}
	}
	void mergeArray(int[] arr,int left,int mid,int right){
		// 合并两个有序子数组arr[left..mid] arr[mid+1..right]
		int i=left,m=mid,j=mid+1,n=right;
		int[] tmp = new int[right-left+1];
		int k=0;
		while(i<=m && j<=n){
			if(arr[i]<=arr[j])
				tmp[k++] = arr[i++];
			else
				tmp[k++] = arr[j++];			
		}
		while(i<=m)
			tmp[k++] = arr[i++];
		while(j<=n)
			tmp[k++] = arr[j++];
		
		// copy tmp to arr
		for(int t=0;t<k;t++)
			arr[left+t] = tmp[t];		
	}
	
	/**
	 * 堆排序:大根堆,每次取堆顶元素,将堆顶元素与最后一个值交换,然后调整堆依次
	 *      整个过程相当于一个不断建堆的过程
	 * 时间复杂度o(nlogn) 空间复杂度o(1)
	 * 不稳定
	 */
	void heapSort(int[] arr){
		// 将初始数组看做已经建好的堆,调整堆
		// parent:i child:2i+1 2i+2
		// 从第一个非叶子节点往上调整
		int len = arr.length;
		int last = len-1;
		while(last >= 0){
			// 调整堆,将最大值放在堆顶,即第一个元素			
			for(int p=(last-1)/2;p>=0;p--){
				int cur = p;
				// 只有第一次需要建立堆,其他时候只要从根节点开始调整堆即可
				if(last != len-1){
					cur = 0;
					p = 0;
				}
				
				while(cur <= (last-1)/2){
					int child = 2*cur+1;
					if(child<last-1 && arr[child] < arr[child+1])
						child += 1;
					if(arr[cur] < arr[child]){
						arr[cur] ^= arr[child];
						arr[child] ^= arr[cur];
						arr[cur] ^= arr[child];
					}
					cur = child;
				}
			}	
			
			// 交换堆顶元素和最后一个元素
			if(arr[0] != arr[last]){
				arr[last] ^= arr[0];
				arr[0] ^= arr[last];
				arr[last] ^= arr[0];
			}
					
			last--;
		}
		
		
	}
	
}

posted @ 2015-08-24 11:49  懒人部落  阅读(216)  评论(0编辑  收藏  举报