转自:http://blog.csdn.net/liyue199512/article/details/52137021?locationNum=1&fps=1
一、冒泡排序
依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的)。第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
- public static void sort(int[] a){
- int temp;
- boolean swap;
- for(int i=0;i<a.length-1;i++){
- swap=false;
- for(int j=0;j<a.length-1-i;j++){
- if(a[j]>a[j+1]){
- temp=a[j];
- a[j]=a[j+1];
- a[j+1]=temp;
- swap=true;
- }
- }
- if(!swap){
- break;
- }
- }
- }
二、直接选择排序
每一趟从待排序的数据元素中选出最小的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
- public static void sort(int[] a){
- for (int i=0;i<a.length-1;i++) {
- int min = i;
- for (int j=i+1;j<a.length;j++){
- if (a[min]>a[j]){
- min=j;
- }
- }
- int temp;
- if (min!=i) {
- temp=a[i];
- a[i]=a[min];
- a[min]=temp;
- }
- }
- }
三、直接插入排序
每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。
- public static void sort(int[] a){
- for(int i=1;i<a.length;i++){
- int temp=a[i];
- int j;
- for(j=i-1;j>=0&&temp<a[j];j--){
- a[j+1]=a[j];
- }
- a[j+1]=temp;
- }
- }
四、快速排序
快速排序是对冒泡排序的一种改进。选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
- public static void sort(int[] a){
- quicksort(a,0,a.length-1);
- }
- public static void quicksort(int[] a,int left,int right){
- int i,j,t,temp;
- if(left>right){
- return;
- }
- temp = a[left];
- i=left;
- j=right;
- while(i!=j){
- while(a[j]>=temp && i<j){
- j--;
- }
- while(a[i]<=temp && i<j){
- i++;
- }
- if(i<j){
- t=a[i];
- a[i]=a[j];
- a[j]=t;
- }
- }
- a[left]=a[i];
- a[i]=temp;
- quicksort(a,left,i-1);
- quicksort(a,i+1,right);
- }
五、堆排序
使用数据结构堆。
堆是完全二叉树或者是近似完全二叉树。
堆满足二个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。
- class Heap{
- private int currentSize;
- private int [] array;
- public Heap(int[] array){
- this.array = array;
- this.currentSize = array.length;
- }
- public int findMin(){
- if(currentSize==0){
- System.out.println("当前堆里已经没有值了!!!!没有最小的了!!!");
- return -1;
- }
- int min = array[0];
-
-
- array[0] = array[currentSize-1];
- currentSize--;
-
-
- down(0);
- return min;
-
- }
- public void down(int hole){
- int child;
- int temp = array[hole];
- for(;hole*2<=currentSize;hole=child){
- child = hole*2;
- if(child!=currentSize&&array[child+1]<array[child]){
- child++;
- }
- if(array[child]<temp){
- array[hole]=array[child];
- }
- else
- break;
-
- }
- array[hole] = temp;
- }
- public void buildHeap(){
- for(int i=currentSize/2-1;i>=0;i--){
- down(i);
- }
- }
- }
- public static void sort(int[] a){
- Heap heap = new Heap(a);
- heap.buildHeap();
- for(int i=a.length-1;i>=0;i--){
- a[i]=heap.findMin();
- }
- }
六、希尔排序(Shell排序)
希尔排序的实质就是分组插入排序,该方法又称缩小增量排序。先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
- public static void sort(int[] a){
- int j;
- for (int gap=a.length/2; gap>0; gap/=2)
- for (int i=0;i<gap;i++){
- for (j=i+gap;j<a.length;j+=gap){
- if (a[j]<a[j-gap]){
- int temp=a[j];
- int k;
- for(k=j-gap;k>=0&&a[k]>temp;k-=gap){
- a[k+gap]=a[k];
- }
- a[k+gap] = temp;
- }
- }
- }
- }
七、归并排序
用分治法思想解决排序问题。
将数组分成二组,如果这二组组内的数据都是各自有序的,那么就可以很方便的将这二组数据合并成有序。可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。
- public static void mergeArray(int a[],int first,int mid,int last,int temp[]){
- int i=first,j=mid+1,m=mid,n=last;
- int k=0;
- while(i<=m&&j<=n){
- if(a[i]<=a[j])
- temp[k++]=a[i++];
- else
- temp[k++]=a[j++];
- }
- while(i<=m)
- temp[k++]=a[i++];
- while(j<=n)
- temp[k++]=a[j++];
- for(i=0;i<k;i++)
- a[first+i]=temp[i];
- }
- public static void mergeSort(int a[],int first,int last,int temp[]){
- if(first<last){
- int mid=(first+last)/2;
- mergeSort(a,first,mid,temp);
- mergeSort(a,mid+1,last,temp);
- mergeArray(a,first,mid,last,temp);
- }
- }
- public static void sort(int a[]){
- int[] temp=new int[a.length];
- mergeSort(a,0,a.length-1,temp);
- }
八、基数排序
先按个位数排序,再按十位数排序,再按百位数排序……
- public static int getDigit(int x, int d){
- int a[]={0,1,10,100,1000,10000,100000};
- return ((x/a[d])%10);
- }
- public static void radixSort(int[] a,int digit){
- final int radix=10;
- int i=0,j=0;
- int[] count=new int[radix];
- int[] bucket=new int[a.length];
-
- for(int d=1;d<=digit;d++){
-
- for(i=0;i<radix;i++) {
- count[i]=0;
- }
-
- for(i=0;i<a.length;i++) {
- j=getDigit(a[i],d);
- count[j]++;
- }
-
- for(i=1;i<radix;i++) {
- count[i]=count[i]+count[i-1];
- }
-
-
- for(i=a.length-1;i>=0;i--) {
- j=getDigit(a[i],d);
- bucket[count[j]-1]=a[i];
- count[j]--;
- }
-
- for(i=0,j=0;i<a.length;i++,j++){
- a[i]=bucket[j];
- }
- }
- }
- public static int[] sort(int[] a) {
- radixSort(a, 2);
- }
九、二叉树排序
排序二叉树的性质如下:
若他的左子树不空,则左子树上所有的结点均小于它的根结点的值。
若他的右子树不空,则右子树上所有的结点均大于它的根结点的值。
他的左右子树也是排序二叉树。
构建排序二叉树,中根遍历就是从小到大排序。
- class Tree{
- private static class TreeNode{
- int element;
- TreeNode left;
- TreeNode right;
- TreeNode(int element){
- this(element,null,null);
- }
- TreeNode(int element,TreeNode left,TreeNode right){
- this.element=element;
- this.left=left;
- this.right=right;
- }
- }
- private TreeNode root;
- public void insert(int x){
- root=insert(x,root);
- }
- public TreeNode insert(int x,TreeNode t){
- if(t==null){
- return new TreeNode(x,null,null);
- }
- if(x<t.element){
- t.left=insert(x,t.left);
- }else if(x>=t.element){
- t.right=insert(x,t.right);
- }
- return t;
- }
- public void printAll(){
- print(root);
- }
- public void print(TreeNode t){
- if(t!=null){
- print(t.left);
- System.out.print(t.element+" ");
- print(t.right);
- }
- }
- }
- public static void sort(int a[]){
- Tree tree = new Tree();
- for(int i=0;i<a.length;i++){
- tree.insert(a[i]);
- }
- tree.printAll();
- }
十、计数排序
找出数在数组中不大于它的数有多少个,从而确定位置。
比较排序算法可以通过决策树模型证明,其下限是O(nlgn),计数排序算法不是一个基于比较的排序算法,所以不受比较排序下限影响。
- public static int[] sort(int[]a){
- int b[]=new int[a.length];
- int max=a[0],min=a[0];
- for(int i:a){
- if(i>max){
- max=i;
- }
- if(i<min){
- min=i;
- }
- }
- int k=max-min+1;
- int c[]=new int[k];
- for(int i=0;i<a.length;i++){
- c[a[i]-min]+=1;
- }
- for(int i=1;i<c.length;i++){
- c[i]=c[i]+c[i-1];
- }
- for(int i=a.length-1;i>=0;--i){
- b[--c[a[i]-min]]=a[i];
- }
- return b;
- }
十一、鸽巢排序
最初时辅助数组中初始化为0,扫描待排序数组时,将待排序序列中的每一个数减去最小值当作辅助数组中的下标自增1。则,扫描完成时,也就间接的完成了排序。之后只需要扫描一遍辅助数组,若辅助数组中有非零的数据,则该位置的下标加上最小值就是待排序数组中原来的数据。借之完成了排序。
- public static void sort(int[]a){
-
- int max=a[0],min=a[0];
- for(int i:a){
- if(i>max){
- max=i;
- }
- if(i<min){
- min=i;
- }
- }
- int k=max-min+1;
- int c[]=new int[k];
- for(int i=0;i<a.length;i++){
- c[a[i]-min]+=1;
- }
- int j=0;
- for(int i=0;i<c.length;i++){
- while(c[i]>0){
- a[j]=i+min;
- j++;
- c[i]--;
- }
- }
- }
对计数排序和鸽巢排序的思考:http://blog.csdn.net/liyue199512/article/details/52149489
十二、桶排序
例如要对大小为[1..1000]范围内的n个整数A[1..n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储(10..20]的整数,……集合B[i]存储((i-1)*10, i*10]的整数,i = 1,2,..100。总共有100个桶。然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。
十三、鸡尾酒排序(鸡尾酒搅拌排序/搅拌排序/ 涟漪排序/来回排序 /快乐小时排序)
是冒泡排序的改进,
从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。
十四、奇偶排序
十五、折半插入排序
是插入排序的改进,
由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
十六、珠排序
http://blog.csdn.net/liyue199512/article/details/52261062
十七、地精排序
http://blog.csdn.net/liyue199512/article/details/52261080
十八、Strand Sort
http://blog.csdn.net/liyue199512/article/details/52261090