java排序方法

此节介绍排序方法



1,冒泡排序
2,选择排序  
3,插入排序  
4,希尔排序
5,快速排序
6,归并排序



一,冒泡排序

算法描叙:

  设待排序记录序列中的记录个数为n
一般地,第i趟起泡排序从1到n-i+1
依次比较相邻两个记录的关键字,如果发生逆序,则交换之。
其结果是这n-i+1个记录中,关键字最大的记录被交换到第n-i+1的位置上,最多作n-1趟。


二,选择排序

  算法描叙:

首先通过n-1次比较,从n个数中找出最小的, 将它与第一个数交换——第一趟选择排序,结果最小的数被安置在第一个元素位置上。
再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,将它与第二个数交换——第二趟选择排序。
重复上述过程,共经过n-1趟排序后,排序结束。


三,插入排序

   算法描叙

记录存放在数组R[0….n-1]中,排序过程的某一中间时刻,R被划分成两个子区间R[0…i-1]和R[i….n-1],其中:前一个子区间是已排好序的有序区;后一个子区间则是当前未排序的部分。

  基本操作:

将当前无序区的第1个记录R[i]插入到有序区R[0….i-1]中适当的位置,使R[0…i]变为新的有序区

  操作细节:

当插入第i(i≥1)个对象时, 前面的r[0], r[1], …, r[i-1]已经排好序。


四,希尔排序

  算法描叙:

先取定一个小于n的整数gap1作为第一个增量,把整个序列分成gap1组。所有距离为gap1的倍数的元素放在同一组中,在各组内分别进行排序(分组内采用直接插入排序或其它基本方式的排序)。
然后取第二个增量gap2<gap1,重复上述的分组和排序。
依此类推,直至增量gap=1,即所有元素放在同一组中进行排序为止。

算法分析:

开始时 gap 的值较大, 子序列中的元素较少, 排序速度较快。
随着排序进展, gap 值逐渐变小, 子序列中元素个数逐渐变多,由于前面大多数元素已基本有序, 所以排序速度仍然很快。
分组后n值减小,n²更小,而T(n)=O(n²),所以T(n)从总体上看是减小了。
Gap的取法有多种。 shell 提出取 gap = n/2 ,gap = gap/2 ,…,直到gap = 1。gap若是奇,则gap=gap+1


五,快速排序

算法描叙:

  任取待排序记录序列中的某个记录(例如取第一个记录)作为基准(枢),按照该记录的关键字大小,将整个记录序列划分为左右两个子序列
左侧子序列中所有记录的关键字都小于或等于基准记录的关键字
右侧子序列中所有记录的关键字都大于基准记录的关键字
基准记录则排在这两个子序列中间(这也是该记录最终应安放的位置)。
然后分别对这两个子序列重复施行上述方法,直到所有的记录都排在相应位置上为止。

基准记录也称为枢轴(或支点)记录。取序列第一个记录为枢轴记录,其关键字为Pivotkey。指针low指向序列第一个记录位置,指针high指向序列最后一个记录位置。



算法分析:

快速排序是一个递归过程,快速排序的趟数取决于递归树的高度。
如果每次划分对一个记录定位后, 该记录的左侧子序列与右侧子序列的长度相同, 则下一步将是对两个长度减半的子序列进行排序, 这是最理想的情况。


六,归并排序

   算法描叙:

设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1。
两两合并,得到 n/2 个长度为2或1的有序子序列。
再两两合并,……如此重复,直至得到一个长度为n的有序序列为止。


package cn.hncu.sortMethods;

public class SortMethods {
	
	/*输出数组中的元素*/
	private static void print(int[] a) {
		for(int num: a){
			System.out.print(num+"\t");
		}
		System.out.println();
	}
	private static void swap(int[] a, int i, int j) {
		int temp;
		temp =a[i];
		a[i] = a[j];
		a[j] = temp;
	}
	
	public static void main(String[] args) {
		int a[] = {0,21,25,49,25,16,15,8,-2,0,-9,67,34,5,12,40};
		//1-1冒泡排序
		bubbleSort(a);
		//1-2优化的冒泡排序
		//bubbleSort2(a);
		
		//2选择排序
		//selectSort(a);
		
		//3-1直接插入排序
		//insertSort(a);
		
		//3-2用二分优化插入排序
		//binaryInsertSort(a);
		
		//4 希尔排序
		//shellSort(a);
		
		
		//5 快速排序
		//quickSort(a,0,a.length-1);
		
		
		//6 归并排序
		//mergeSort(a,0,a.length-1);
		
		
		print(a);
	}
	
	private static void mergeSort(int[] a, int left, int right) {
		if(left<right){//至少有2个元素
			int mid = (left+right)/2; //二分,取中点
			//把序列拆分成两个子序列:[left,mid] 和  [mid+1,right]
			//同时还要对分解后的子序列分别进行递归“归并排序”
			mergeSort(a,left,mid);
			mergeSort(a,mid+1,right);
			
			//把前面两个已经排好序的子序列进行归并
			int b[] = new int[a.length];
			merge(a,b,left,mid,right);
			copyArray(a,b,left,right);
		}
	}
	
	private static void copyArray(int[] a, int[] b, int left, int right) {
		for(int i=left;i<=right;i++){
			a[i] = b[i];
		}
	}
	//把两个已经排好序的子序列(a[left,mid]和a[mid+1,right]) 合并成一个 ( b[left,right] )
	private static void merge(int[] a, int[] b, int left, int mid, int right) {
		int p = left;
		int r=mid+1;
		int k=left;
		while( p<=mid && r<=right ){
			if(a[p]<=a[r]){
				b[k++] = a[p++];
			}else{
				b[k++] = a[r++];
			}
		}
		//此时,肯定有一个子序列中的元素全部移到b[]数组,因此,只要把还未移完的子序列当中的所有剩余元素直接对拷到数组b[]当中即可
		if(p>mid){//左子序列已经完成。因此剩下的是右序列,对拷右序列当中的剩余元素即可
			for(int i=r;i<=right;i++){
				b[k++]=a[i];
			}
		}else{//对拷左子序列中的剩余元素
			for(int i=p;i<=mid;i++){
				b[k++]=a[i];
			}
		}
	}
	
	
	private static void quickSort(int[] a, int p, int r) {
		if(p<r){
			//把数组划分成两个子数组和一个元素(枢轴):
			//用枢轴a[q]把整数数组划分成 ==>  a[p,q-1] , a[q] , a[q+1,r]
			int q = partition(a,p,r); //a[q]
			quickSort(a,p,q-1);//排左边的子数组a[p,q-1]
			quickSort(a,q+1,r);//排右边的子数组a[q+1,r]
		}
		
	}
		private static int partition(int[] a, int p, int r) {
		//优化:采用随机选择策略确定枢轴----随机选取数组当中的一个元素,和第一个元素进行交换。之后,以第一个元素作为枢轴进行划分
		int rand = (int)(Math.random()*(r-p));//rand为区间内的随机序号(第几个)//p=10000, r=15000
		swap(a,p,p+rand);
		
		int i=p;//第一个元素定为枢轴
		int j=r+1;
		int x=a[p];
		
		while(true){
			while(a[++i]<x && i<r);//定位指针i,找比x大的元素 <--为的是找要交换到右边的"非法"元素
			while(a[--j]>x);//定位指针j <--为的是找要交换到左边的"非法"元素
			if(i>=j){
				break;
			}
			swap(a,i,j);
		}
		swap(a,p,j);//枢轴a[p]要换到中间位置
		return j;
	}
	
	
	//4 希尔排序
	private static void shellSort(int[] a) {
		//进行分组,初始步长设为数组长度的一半即n/2,然后依次减半,直到最后取1
		for(int gap=(a.length+1)/2;gap>0;){
			//组内排序
			for(int i=0;i<a.length-gap;i++){//定位到每一个元素
				for(int j=i;j<a.length-gap;j+=gap){
					if(a[j]>a[j+gap]){
						swap(a,j,j+gap);
					}
				}
			}
			//for循环的修正
			if(gap>1){
				gap = (gap+1)/2;
			}else if(gap==1){
				break;
			}
		}
		
		
	}
	
	
	//3-2用二分优化插入排序
	private static void binaryInsertSort(int a[]){
		for(int i=0;i<a.length-1;i++){
			int temp=a[i+1];
			int low=0;
			int high=i;
			int mid;
			//在low与 high之间的区域内进行二分查找,以确定新元素的插入位置
			while(low<=high){
				mid = (high+low)/2;
				if(a[mid]>temp){//若待插入的数小于中间元素a[mid],则目标落于左半区
					high = mid-1;
				}else{//若待插入的数大于等于中间元素a[mid],则目标落于右半区
					low= mid+1;
				}
			}
			//搜索的最后一个小区间的high位置即是查找目标,因此新元素的插入位置即是high+1
			//把原来从high到i范围内的元素依次往后移一个位置
			for(int j=i;j>high;j--){
				a[j+1] = a[j];
			}
			a[high+1] = temp;
		}
		
	}
	
	
	//3-1直接插入排序
	private static void insertSort(int[] a) {
		for(int i=0;i<a.length-1;i++){
			int temp=a[i+1];
			int j=i;
			//插入第i个数
			//从后往前搜,发现a[j]>temp时,则把a[j]后移到j+1的位置,继续往前搜。
			while(a[j]>temp){
				a[j+1]=a[j];
				j--;
				if(j<0){
					break;
				}
			}
			//否则即a[j]<=temp时,直接把待插入的数放到a[j+1]处
			a[j+1]=temp;
		}
	}
	
	
	//2选择排序
	private static void selectSort(int[] a) {
		for(int i=0;i<a.length-1;i++){
			int j,k;
			for(j=i+1,k=i;j<a.length;j++){
				if(a[j]<a[k]){
					k=j;
				}
			}
			if(k!=i){
				swap(a,i,k);
			}
		}
	}
	
	/*1-1冒泡排序*/
	private static void bubbleSort(int[] a) {
		//冒n-1次,每一次排一个数,最后一个不用排
		for(int i=0;i<a.length-1;i++){
			//第i趟,从1~n-i-1,两两相邻的数进行判断,若逆顺则交换
			for(int j=0;j<a.length-i-1;j++){
				if(a[j]>a[j+1]){//升序
					swap(a, j, j+1);
				}
			}
		}
	}
	/*1-2冒泡排序优化*/
	private static void bubbleSort2(int[] a) {
		boolean flag=false;//表示整个序列还没排好
		//冒n-1次,每一次排一个数,最后一个不用排
		for(int i=0;i<a.length-1;i++){
			
			flag = true;//假设整个序列已经完成排序
			for(int j=0;j<a.length-i-1;j++){
				if(a[j]>a[j+1]){
					swap(a, j, j+1);
					//如果有交换,说明前面的假设不成立
					flag = false;
				}
			}
			if(flag){//如果前面的假设成立即整个序列已经排好序,则函数返回
				return;
			}
		}
	}
	

}







ppt  文档 链接:http://pan.baidu.com/s/1c0vzh9u 密码:23yt






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值