排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操做。排序算法,就是如何使得记录按照要求排列的方法。算法
排序算法大致可分为两种:shell
一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。数组
另外一种是非比较排序,时间复杂度能够达到O(n),主要有:计数排序,基数排序,桶排序等函数
稳定:若是a本来在b前面,而a=b,排序以后a仍然在b的前面。性能
不稳定:若是a本来在b的前面,而a=b,排序以后 a 可能会出如今 b 的后面。spa
时间复杂度:对排序数据的总的操做次数。反映当n变化时,操做次数呈现什么规律。code
空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。 blog
一、冒泡排序排序
* 冒泡排序
* 冒泡排序是一种极其简单的排序算法,也是我所学的第一个排序算法。它重复地走访过要排序的元素,依次比较相邻两个元素
* ,若是他们的顺序错误就把他们调换过来,直到没有元素再须要交换,排序完成。这个算法的名字由来是由于越小(或越大)的
* 元素会经由交换慢慢“浮”到数列的顶端。
*
* 冒泡排序算法的运做以下:
* (1)比较相邻的元素,若是前一个比后一个大,就把它们两个调换位置。
* (2)对每一对相邻元素做一样的工做,从开始第一对到结尾的最后一对。这步作完后,最后的元素会是最大的数。
* (3)针对全部的元素重复以上的步骤,除了最后一个。
* (4)持续每次对愈来愈少的元素重复上面的步骤,直到没有任何一对数字须要比较。递归
public class BubbleSort { public static int[] sort(int[] arr){ int temp=0; int n=arr.length; for(int i=1;i<n;i++){ for(int j=0;j<n-i;j++){ if(arr[j]>arr[j+1]){ temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } //输出每次排序完成后的数组 PrintArray.printArray(arr); System.out.println(); } return arr; } }
二、插入排序
插入排序在实现上,一般采用in-place排序(即只需用到O(1)的额外空间的排序),于是在从后向前扫描过程当中,
* 须要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
*
* 具体算法描述以下:
* 从第一个元素开始,该元素能够认为已经被排
* 取出下一个元素,在已经排序的元素序列中从后向前扫描
* 若是该元素(已排序)大于新元素,将该元素移到下一位
* 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
* 将新元素插入到该位置后
* 重复步骤2~5*/
public class InsertSort { public static int[] sort(int[] arr){ int n=arr.length; for(int i=1;i<n;i++){ int num=arr[i]; //当前位置前一个位置 int j=i-1; while(j>=0 && arr[j]>num){ arr[j+1]=arr[j]; j--; } arr[j+1]=num; PrintArray.printArray(arr); System.out.println(); } return arr; } }
三、希尔排序
/*希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。
* 希尔排序是基于插入排序的如下两点性质而提出改进方法的
* 插入排序在对几乎已经排好序的数据操做时,效率高,便可以达到线性排序的效率
* 但插入排序通常来讲是低效的,由于插入排序每次只能将数据移动一位
* 希尔排序经过将比较的所有元素分为几个区域来提高插入排序的性能。这样可让一个元素能够一次性地朝最终位置前进一大步。
* 而后算法再取愈来愈小的步长进行排序,算法的最后一步就是普通的插入排序,可是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
* 假设有一个很小的数据在一个已按升序排好序的数组的末端。若是用复杂度为O(n^2)的排序(冒泡排序或直接插入排序),可能会进行n次的
* 比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,因此小数据只需进行少数比较和交换便可到正确位置。
* */
public static void shellSort(int[] arr){ for(int r=arr.length/2;r>=1;r=r/2){ int temp; int j = 0; for(int i=r;i<arr.length;i=i+1){ temp=arr[i]; j=i-r; while(j>=0&&temp<arr[j]){ arr[j+r]=arr[j]; j=j-r; } arr[j+r]=temp; } } for(int a:arr) System.out.print(a+" "); System.out.println(); }
四、选择排序
* 选择排序也是一种简单直观的排序算法。它的工做原理很容易理解:初始时在序列中找到最小(大)元素,放到序列
* 的起始位置做为已排序序列;而后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此
* 类推,直到全部元素均排序完毕。
*
* 注意选择排序与冒泡排序的区别:
* 冒泡排序经过依次交换相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置;而选择排序每遍
* 历一次都记住了当前最小(大)元素的位置,最后仅需一次交换操做便可将其放到合适的位置*/
public static int[] sort(int[] arr){ int n=arr.length; for(int i=0;i<n-1;i++){ int minNum=i; for(int j=i+1;j<n;j++){ if(arr[minNum]>arr[j]){ minNum=j; } } int temp=arr[i]; arr[i]=arr[minNum]; arr[minNum]=temp; } return arr; }
五、快速排序
*快速排序,顾名思义,是一种速度快,效率高的排序算法。
快排原理:
在要排的数(好比数组A)中选择一个中心值key(好比A[0]),经过一趟排序将数组A分红两部分,
其中以key为中心,key右边都比key大,key左边的都key小,而后对这两部分分别重复这个过程,
直到整个有序。
整个快排的过程就简化为了一趟排序的过程,而后递归调用就好了。
一趟排序的方法:
1,定义i=0,j=A.lenght-1,i为第一个数的下标,j为最后一个数下标
2,从数组的最后一个数Aj从右往左找,找到第一小于key的数,记为Aj;
3,从数组的第一个数Ai 从左往右找,找到第一个大于key的数,记为Ai;
4,交换Ai 和Aj
5,重复这个过程,直到 i=j
6,调整key的位置,把A[i] 和key交换
public static int[] sort(int[] arr,int l,int r){ int size=arr.length; if(l<r){ int i=l,j=r,x=arr[l]; while(i<j){ while(i<j&&arr[j]>x) j--; if(i<j) arr[i++]=arr[j]; while(i<j&&arr[i]<x) i++; if(i<j) arr[j--]=arr[i]; } arr[i]=x; sort(arr, l, i-1); sort(arr, i+1, r); } return arr; }