java实现选择、插入、归并、快速排序以及优化

以下是O(n2)级别的算法

选择排序

一共n-1轮循环,第一轮将第一个数与它后面所有数比较,若它大于后面某个数则交换,然后继续拿这个新的索引为0的数与后面的数继续比较,直到这一轮循环结束。第二轮循环则拿索引为1的数与它后面的数继续比较(重复上一轮的操作)。
public static void selectsort(int[] arr){
		for(int i=0;i<arr.length-1;i++){        //控制排序的轮数同时指定下标范围
			for(int j=i+1;j<arr.length;j++){     //被比较数的下表范围
				if(arr[i]>arr[j]){
					//交换
					huan(arr,i,j);
				}
			}
		}
	}

插入排序(对于近乎有序的数组,其时间复杂度会降至O(N))

从数组第二个元素开始,比较第二个与第一个元素,后面的更小则交换,就像玩扑克牌一样,抽完牌后将牌插入到前面合适的位置排序
//插入排序(稳定排序:相等值的相对位置不变)
	public static void insertsort(int[] arr,int n){
		for(int i=1;i<n;i++){
			//寻找arr[i]在前面是否有合适的插入位置
			for(int j=i;j>0&&arr[j]<arr[j-1];j--){	
					huan(arr,j,j-1);		
			}
		}
	}

优化版插入排序

没有交换操作,大大减少计算时间。首先复制一份待插入的arr[i](int a=arr[i]),若a比它前一个位置(i-1)的数小则将前一个数赋值给后一个数(即a[i]),再比较a和a[i-2],若a小于a[i-2]则a[i-2]赋值给a[i-1],再比较a和a[i-3],,,直到a要比较的数不存在(即a[0]前一个数)或a大于它比较的数,则将a赋值给a[0]或它比较的数的后一个数。
public static void Betterinsertsort(int[] arr,int n){
		for(int i=1;i<n;i++){
			//寻找arr[i]在前面是否有合适的插入位置
			int a=arr[i];
			int j;//保存元素a应该插入的位置
			for(j=i;j>0&&arr[j-1]>a;j--){	
					arr[j]=arr[j-1];		
			}
			arr[j]=a;
		}
	}

以下是O(nlogn)级别的算法

归并排序

//自顶向下归并排序         (稳定排序:相等值的相对位置不变)
	public static void mergesort(int[] arr,int n){
		__mergesort(arr,0,n-1);
	}
	//递归使用归并排序,对arr[l,r]的范围进行排序
	public static void __mergesort(int[] arr,int l,int r){
		
//		if(l>=r)        //这是递归倒底时的一般处理
//			return;
	
		if(r-l<10){      //当递归过程中的数组的长度已缩小到一定程度,有序性的概率就大了,用插入排序更快
			insertsort2(arr,l,r);
			return;
		}
		
		
		int mid=(l+r)/2;
		__mergesort(arr,l,mid);
		__mergesort(arr,mid+1,r);
		if(arr[mid]>arr[mid+1])     //若arr[mid]<arr[mid+1],则数组已经有序,if判断下减少了归并步骤
		    __merge(arr,l,mid,r);
	}
	//将arr[l,mid]和arr[mid+1,r]两个部分进行归并
	public static void __merge(int[] arr,int l,int mid,int r){
		int aux[]=new int[r-l+1];
		for(int i=l;i<=r;i++){
			aux[i-l]=arr[i];   //i-l:减去偏移量
		}
		int i=l,j=mid+1;  //分别指向两个数组的开头
		for(int k=l;k<=r;k++){
			
			if(i>mid){   //若aux[]左半边的元素都访问完了,则将aux右半边剩余元素赋值回arr[]
				arr[k]=aux[j-l];
				j++;
			}
			else if(j>r){  //若aux[]右半边的元素都访问完了,则将aux左半边剩余元素赋值回arr[]
				arr[k]=aux[i-l];
				i++;
			}
			else if(aux[i-l]<aux[j-l]){ //在aux[]中比较后,将正确结果赋值回arr[]
				arr[k]=aux[i-l];
				i++;
			}else{
				arr[k]=aux[j-l];
				j++;
			}
			
		}
	}

快速排序

然而这样写的快速排序有个弊端,当数组是近乎有序的,那选定的最左边用来参照的数"v"极有可能是最小的,则并不能将数组分成小于"v"和大于"v"的两部分,就退化成了O(N2)的算法。不过改进一下,避免这种情况还是简单的,arr[l,r]中随机获得一个数将它和arr[l]交换,再将arr[l]赋值给v。
public static void quicksort(int[] arr,int n){
		__quicksort(arr,0,n-1);
	}
	public static void __quicksort(int arr[],int l,int r){
//		if(l>=r)
//			return;
		
		if(r-l<10){      //当递归过程中的数组的长度已缩小到一定程度,有序性的概率就大了,用插入排序更快
			insertsort2(arr,l,r);
			return;
		}
		int p=__partition(arr,l,r);
		__quicksort(arr,l,p-1);
		__quicksort(arr,p+1,r);
	}
	//对arr[l,r]进行__partition操作
	//返回p,使得arr[l,p-1]<arr[p];arr[p+1,r]>arr[p]
	public static int __partition(int arr[],int l,int r){
		int v=arr[l];
		//使得arr[l+1...j]<v;arr[j+1..r)>v
		int j=l;       //j指向小于v的左侧数据最后一个元素
		for(int i=l+1;i<=r;i++){
			if(arr[i]<v){
				huan(arr,j+1,i);
				j++;
			}
		}
		huan(arr,l,j);
		return j;
	}

三路快速排序

当数组中存在大量等于v(参照数)的数,同样导致"<v"和">v"的两部分严重不平衡,因此把整个数组分成"<v"和"=v"和">v"三部分,然后继续对"<v"和“>v”部分进行三路快速排序。
//三路快速排序(将arr[l,r]分为<v,=v,>v三部分)适合重复数据多的数组
	//之后递归<v;>v两部分继续进行三路递归排序
	public static void quicksort3ways(int[] arr,int n){
		__quicksort3ways(arr,0,n-1);
	}
	
	public static void __quicksort3ways(int arr[],int l,int r){

		if(r-l<10){      //当递归过程中的数组的长度已缩小到一定程度,有序性的概率就大了,用插入排序更快
			insertsort2(arr,l,r);
			return;
		}
		//partition
		huan(arr,l,new Random().nextInt(r-l+1)+l);
		int v=arr[l];
		
		int lt=l;   //arr[l+1,lt]<v
		int gt=r+1;   //arr[gt,r]>v
		int i=l+1;  //arr[lt+1,i)==v
		while(i<gt){
			if(arr[i]<v){
				huan(arr,i,lt+1);
				lt++;
				i++;
			}else if(arr[i]>v){
				huan(arr,i,gt-1);
				gt--;
			}else{   //arr[i]==v
				i++;
			}
		}
		huan(arr,l,lt);
		
		__quicksort3ways(arr,l,lt-1);
		__quicksort3ways(arr,gt,r);
	}

PS:发现了一个BUG修复了一下,就是在归并、快速、三路快速排序中的以下程序段:
		if(r-l<10){      //当递归过程中的数组的长度已缩小到一定程度,有序性的概率就大了,用插入排序更快
			insertsort2(arr,l,r);
			return;
		}
应修改成这样,新写了一个插入排序,之前传入的是arr,r-l+1,这样导致插入排序排序的部分跟我想让它排序的不是一个部分,,,,


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值