排序算法总结

排序算法总结


排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。

当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序。
快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短, 因此快速排序通常是首选的排序

1、插入排序

先将数组的第1个元素看成是一个有序的子数组,然后从第2个元素开始逐个进行插入,直至整个数组有序为止。 时间复杂度O(n^2)
public static void insertSort(int[] arr) {
	if(arr==null || arr.length==0)
		return;
	for(int i=1;i<arr.length;i++){
		int j=i;
		int target=arr[i];
		while(j>0 && target<arr[j-1]){
			arr[j]=arr[j-1];
			j--;		
		}
		arr[j]=target;
	}
} 

2、希尔排序

希尔排序(Shell Sort)是插入排序的一种,其基本思想是:把数组按下标的一定增量分组,对每组进行插入排序;随着增量逐渐缩小一半,数组逐渐接近有序,当增量减至1时,整个数组有序了,算法便终止。

public class Shell_sort {
	
	public static void shellSort(int[] date){
		int n=date.length;
		for(int i=n/2;i>0;i=i/2){
			for(int j=0;j<i;j++){
				incrementalInsertionSort(date,j,n-1,i);
			}
		}
	}
	
	private static void incrementalInsertionSort(int[] a,int first,int last,int space){
		int unsorted,index;
		for(unsorted=first+space;unsorted<=last;unsorted=unsorted+space){
			int firstUnsorted=a[unsorted];
			for(index=unsorted-space;(index>=first)&&(firstUnsorted<a[index]);index=index-space)
				a[index+space]=a[index];
			a[index+space]=firstUnsorted;
		}
	}
}

3、选择排序

从数组中选出最小的值放在第1位置,然后在剩下的数中选出最小的值放在第2位置,以此类推,就会的到有序的数组。
public class SelectSort {

	public static void selectSort(int[] arr) {
		int minIndex = 0;
		for(int i=0; i<arr.length-1; i++) {
			minIndex = i;
			for(int j=i+1; j<arr.length; j++) {
				if(arr[j] < arr[minIndex])
					minIndex = j;
			}
			if(minIndex!=i)
				swap(arr, i, minIndex);
		}
	}  

	public static void swap(int[] arr, int i, int j) {  
		int temp = arr[i];  
		arr[i] = arr[j];  
		arr[j] = temp;  
	}
}

4、堆排序

基本思想:
  • 先将待排序数组建成一个最大堆,此堆为初始的无序区
  • 将堆顶元素与无序区最后一个元素交换,由此得到新的无序区和有序区
  • 重复以上两个过程,直到无序区只有一个元素为止
下面是一个堆排序的例子:

5、冒泡排序

自上而下地不断比较两个相邻的元素,把较大的数往下沉,把较小的数往上冒,最后得到有序的数组。
public class BubbleSort {  

	public static void bubbleSort(int[] arr){
		if(arr == null || arr.length == 0)
			return ;
		for(int i=0;i<arr.length-1;i++){
			for(int j=arr.length-1;j>i;j--){
				if(arr[j]<arr[j-1])
					swap(arr,j-1,j);
			}
		}
	}

	public static void swap(int[] arr,int i,int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

6、快速排序(分治法)

基本思想:
1、先从数组中取出一个数作为基准数
2、进行分区,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边
3、再对左右区间重复第二步,直到各区间只有一个数。

对挖坑填数进行总结·
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
public static void quickSort(int[] arr, int l, int r){
	if (l<r){
		int i=l, j=r, x=arr[l];
		while(i<j){
			while(i<j && arr[j]>=x) // 从右向左找第一个小于x的数 
				j--;
			if(i<j)
				arr[i++]=arr[j];
			while(i<j && arr[i]<x) // 从左向右找第一个大于等于x的数  
				i++;
			if(i<j)
				arr[j--]=arr[i];
		}
		arr[i]=x;
		quickSort(arr,l,i-1); // 递归调用  
		quickSort(arr,i+1,r);
	}
}

7、归并排序(分治法)

归并排序将一个数组分为两个子数组,然后递归地将每个子数组再分成两个子数组,直到每个子数组只含有一个元素为止。从这里开始进入归并状态,两个含一个元素的子数组归并为一个含两个元素的子数组,以此类推,最后得到一个有序的数组。
归并的过程——将两个有序的子数组合并成一个有序的数组。

public class Merge_sort {
	//调用mergeSort(date,0,date.length-1)  
	public static void mergeSort(int[] date,int first,int last){  
		if(first<last){  
			int mid=(first+last)/2;  
			mergeSort(date, first, mid);  
			mergeSort(date, mid+1, last);  
			merge(date, first, mid, last);  
		}  
	}  

	private static void merge(int[] a,int first,int center,int last){  
		int [] tmpArr=new int[a.length];  
		int mid=center+1;  
		int third=first;  
		int tmp=first;  
		while(first<=center&&mid<=last){  
			if(a[first]<=a[mid]){  
				tmpArr[third]=a[first];  
				first++;  
			}else{  
				tmpArr[third]=a[mid];  
				mid++;  
			}  
			third++;  
		}  
		while(mid<=last)  
			tmpArr[third++]=a[mid++];  
		while(first<=center)  
			tmpArr[third++]=a[first++];  
		while(tmp<=last)  
			a[tmp]=tmpArr[tmp++]; 
	}  
}

8、基数排序

基数排序不比较对象,而是将数组元素作为长度相等的的字符串对待。若元素为整数,先把每个元素按最大数的位数在数前以0补全,分成10个桶,先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,按顺序装回原数组;再以百位数划分.....以此类推,最终得到有序数组。基数排序是最快的,时间复杂度为O(n),但不适用于所有数据。
public class RadixSort{

	//调用radixSort(data,10);
	public static void radixSort(int[] data, int radix){
		int[] tmp=new int[data.length];
		int[] buckets = new int[radix];
		for (int i=0,rate=1;i<data.length-1;i++){
			Arrays.fill(buckets, 0);
			System.arraycopy(data, 0, tmp, 0, data.length);// 将data中的元素完全复制到tmp数组中  
			for (int j = 0; j < data.length; j++){
				int subKey = (tmp[j]/rate) % radix;
				buckets[subKey]++;
			}
			for (int j = 1; j < radix; j++)
				buckets[j] = buckets[j] + buckets[j - 1];  
			for (int m = data.length - 1; m >= 0; m--){
				int subKey = (tmp[m] / rate) % radix;
				data[--buckets[subKey]] = tmp[m];
			}
			rate *= radix;
		}  
	}
}

8、各种排序的稳定性,时间复杂度和空间复杂度总结


稳定性:所有相等的数经过某种排序方法后,仍能保持它们在排序之前的相对次序,就称这种排序方法是稳定的。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值