总结的比较重要的排序算法

对于每种排序算法,需要理解以下问题:
1.算法思想是什么
2.时间复杂度
3.稳定性
4.什么情况下适用?

基于比较的排序,已证明,基于比较的排序算法时间复杂度不会低于O(nlgn)最好的情况能达到这个下限,包括:插入排序/希尔排序/选择排序/堆排序/冒泡排序/归并排序/快速排序

不是基于比较的排序算法有望将时间复杂度降到O(nlgn)以下,适当的作为补偿,待排序的序列也必须有一定的规律,包括:计数排序/基数排序/桶排序


插入排序

算法思想:从数组的第二个元素开始遍历整个数组。针对每个元素,依次将其前面的所有元素从后向前和进行比较,大于它的元素均向后移动,最后将该元素插入。

时间复杂度:O(n^2)。最好情况下,已经有序O(n),最坏情况下逆序O(n^2)

稳定性:稳定,原址排序

适用场景:当数组已经基本有序时,使用插入排序能有效减少移动的次数,时间消耗最少。


希尔排序

算法思想:也属于插入排序,直接插入排序在当序列恰好为顺序时,时间消耗为O(n),因此若某个序列已基本有序,直接插入排序的效率就会提高,基于这个思想,通过比较相距一定间隔的元素来工作,各趟比较所用距离随着算法的进行而减小,直至只比较相邻元素的最后一趟排序,因此也称递减增量排序算法。

时间复杂度:对插入算法的改进,低于O(n^2),具体与选择的增量序列有关

稳定性:不稳定,原址排序

使用场景:时间复杂度和增量序列的联系紧密,好的增量序列才能保证有好的时间复杂度,使用较少。


选择排序
算法思想:从所有序列中先找到最小的,然后放到第一个位置,之后再看剩余元素中最小的,放到第二个位置……以此类推

时间复杂度:O(n^2)

稳定性:不稳定,原址排序

适用场景:理解简单,比较元素较少时都可以使用,因为要遍历整个数组,任何情况下性能都很差。


堆排序

算法思想:也属于一种选择排序。由于一般的选择排序在寻找最大值时需要遍历数组,遍历数组的复杂度为O(n),因此造成了时间的浪费,如若将待排序的数组进行一系列整理,例如将其整理成有特点的堆这种数据结构,由于其删除最大值的复杂度仅仅为O(lgn),那么我们有理由相信,能将选择排序的时间复杂度降低到O(nlgn)

时间复杂度:O(nlgn)

稳定性:不稳定,原址排序

适用场景:没有特定的场景,只是没有快速排序用的多。


冒泡排序

算法思想:从第一个元素开始相邻的两个元素两两比较,按照小数在上大数在下的规则交换,一趟下去大数沉底。再从第一个元素开始两两比较相邻两个元素,直到倒数第二个元素....

时间复杂度:O(n^2),改进后再最好情况下达到O(n)

稳定性:不稳定,原址排序

适用场景:容易理解,比较元素较少时都可以使用。


归并排序

算法思想:分治思想,将数组分成两部分,如果这两部分均有序,那么便可在O(n)的时间内合并成一个完整的有序数组。由此,将区间划分下去,直到每个区间只有一个元素,即可认为已经有序,然后两两合并,而合并两个有序数组只需要O(n)的复杂度。

时间复杂度:O(nlgn)

稳定性:稳定,需要额外辅助空间

适用场景:同复杂度的的情况下可选,更多的用在外排序中。


快速排序

算法思想:分治思想,和归并排序相比,归并排序主要工作在于合并操作,而快速排序在于划分。划分数组为两部分,左边部分小于中间的值,右边部分大于中间的值,然后递归的对左右两边进行快速排序,这里,对数组的划分只需要O(n)的复杂度.

时间复杂度:O(nlgn),最差情况划分为1,n-1,此时复杂度为O(n^2)其他情况均为O(nlgn),期望为O(nlgn)

稳定性:不稳定,原址排序

适用场景:顾名思义,使用当然是最多的,整体情况下是最快的。


public class paixu {
	/*
	 * 插入排序 第二个与前一个比较  第三个与前两个比较 第四个与前三个比较
	 * 正序时时间复杂度为O(n),这时最好的情况。反序时,故时间复杂度为O(n2)*/
	public static  void charusort(int [] arr){
		for(int i=0;i<arr.length-1;i++)
			
			for(int j=0;j<=i;j++){
				if(arr[i+1]<arr[j])
				{	int s=arr[j];
					arr[j]=arr[i+1];
					arr[i+1]=s;
				}
					
					
			}
	}
	
	/*
	 * 希尔排序   分组和插入排序相结合
	 * 基本思想:取一个小于n的整数d1=N/2作为第一个增量,把文件的全部记录分成d1个组。
	 * 所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;
	 * 然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),
	 * 即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。
	 * 
	 * 
	 * 所以希尔排序是不稳定的。

  希尔排序的时间性能优于直接插入排序, 希尔排序的平均时间复杂度为O(nlogn)*/
	public static void shellsort(int []arr){
		int d=arr.length;
		while(true){
			d=d/2;
			for(int x=0;x<d;x++){
				for(int i=0;i<arr.length-d;i=i+d)
					for(int j=0;j<=i;j=j+d){
						if(arr[i+d]<arr[j])
						{	int s=arr[j];
							arr[j]=arr[i+d];
							arr[i+d]=s;
						}
							
							
					}
				
			}if(d == 1){
					               break;
					            }
		}
	}
	
	/*
	 * 选择排序  选出最小的和第一个交换   和第二个交换 第三个交换
	 * 简单选择排序是不稳定的排序。

  时间复杂度:T(n)=O(n2)。*/
	public static void selectsort(int []arr){
		for(int i=0;i<arr.length;i++){
			int min=arr[i];
			int n=i;
			  for(int j=i+1;j<arr.length;j++){
				               if(arr[j]<min){  //找出最小的数
				                    min = arr[j];
			                   n = j;
			              }
			            }
			  			arr[n] = arr[i];
			              arr[i] = min;
		}
	}
	
	public static void bubblesort(int []arr){
		for(int i=0;i<arr.length;i++)
			for(int j=0;j<arr.length-1-i;j++)
			{
				if(arr[j]>arr[j+1]){
				                    int temp = arr[j];
					                    arr[j] = arr[j+1];
				                    arr[j+1] = temp;
					                 }
			}
	}
	
	/*快速排序
	 * */
	public static void quick(int []arr){
		quickSort(arr,0,arr.length-1);
	}

    private static void quickSort(int[] a, int low, int high) {
        if(low<high){ //如果不加这个判断递归会无法退出导致堆栈溢出异常
            int middle = getMiddle(a,low,high);
            quickSort(a, 0, middle-1);
            quickSort(a, middle+1, high);
        }
    }

    private static int getMiddle(int[] a, int low, int high) {
        int temp = a[low];//基准元素
        while(low<high){
            //找到比基准元素小的元素位置
            while(low<high && a[high]>=temp){
                high--;
            }
            a[low] = a[high]; 
            while(low<high && a[low]<=temp){
                low++;
            }
            a[high] = a[low];
        }
        a[low] = temp;
        return low;
    }

    
    //归并排序  
    public static void gunbin(int []arr){
    	mergesort(arr,0,arr.length-1);
    }
	private static void mergesort(int[] arr, int i, int j) {
		if(i<j){ int middle = (i+j)/2;
			mergesort(arr,0,middle);
			mergesort(arr,middle+1,j);
			hebinsort(arr,i,middle,j);
		}
		
	}

	private static void hebinsort(int[] arr, int i, int middle, int j) {
		int [] brr=new int [arr.length];
		int mid=middle+1;
		 int tmp = i;
		 int third = i;
		 while(i<=middle&&mid<=j){
			 if(arr[i]<arr[mid]){
				 brr[third++]=arr[i++];}
				 else {
					 brr[third++]=arr[mid++];
				 }
			 
		 }
		 
		 while(i<=middle){
			 brr[third++]=arr[i++];
		 }
		 while(mid<=j){
			 brr[third++]=arr[mid++];
		 }
		 while(tmp<=j){
			            arr[tmp] = brr[tmp++];
			        }
			
				
		
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		 int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1};
		 gunbin(a);
		 for(int i=0;i<a.length;i++){
			 System.out.println(a[i]);
		 }
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值