一、八大排序简介
- 插入排序(直接插入排序,二分插入排序,shell排序)
- 交换排序(冒泡排序,快速排序)
- 选择排序(直接选择排序,堆排序)
- 归并排序
- 分配排序(基数排序)
1. 插入排序
思想:将每一个待排序序列,每一步都按顺序码插入到前面已经排序的子序列中,直到全部插入排序完为止。
/** * 直接插入排序 * 思想:两次for循环,时间复杂度:O(n^2),空间复杂度:O(1) * @param a * @return */ public static int[] insertionSortDirect(int []a){ for(int j=1;j<a.length;j++){ int t=a[j];//待插入元素 int i; for(i=j-1;i>=0 && a[i]>t;i--){ a[i+1]=a[i];//将大于插入元素的往后移动一位 } a[i+1]=t; } return a; }
/** * 二分插入排序 * 思想:按照折半查找,减少查找次数;时间复杂度:O(nlog2n);空间复杂度:O(1) */ public static int[] insertionSortTwo(int []a){ for(int i=1;i<a.length;i++){ int t=a[i],right=i-1,left=0,mid;
while(right>=left){
mid=(right+left)/2;
if(a[mid]<t){
left=mid+1;
}else{
right=mid-1;
}
}
for(int j=i-1;j>=left;j--){
a[j+1]=a[j];//移动元素
}
if(left!=i){
a[left]=t;
}
}
return a;
}
2.Shell排序
/** * Shell排序 * 相当于分组排序,将间隔dk的元素放在同一组里,进行排序,时间复杂度:O(nlog2n);空间复杂度:O(1) */ public static int[] insertSortShell(int a[],int i){ int dk=a.length/i; while(dk>=1){ insertShell(a, dk); dk=dk/2; } return a; } public static void insertShell(int a[],int dk){ for(int j=1;j<a.length;j++){ int t=a[j];//待插入元素 int i; for(i=j-dk;i>=0&&a[i]>t;i=i-dk){ a[i+dk]=a[i];//将大于插入元素的往后移动一位 } a[i+dk]=t; } }
3.简单选择排序
/** * 简单选择排序 * 思想:通过一次循环,找到最小值的下标,把最小值放在最前面,再在后面的数中继续寻找,直到倒数第二个 */ private static void simpleSelectSort(int []a){ int min; for(int i=0;i<a.length-1;i++){ min=i; for(int j=i+1;j<a.length;j++){//找到最小值得下标 if(a[j]<a[min]){ min=j; } } swap(a,i,min); } } private static void swap(int a[],int i,int min){ if(i==min){ return; } a[i]+=a[min]; a[min]=a[i]-a[min]; a[i]=a[i]-a[min]; }
/** * 二元选择排序 * 思想:与简单选择排序不同的是分别找出最大和最小 */ private static void binarySelectSort(int []a){ int max,min; for(int i=0;i<a.length/2;i++){ min=max=i; for(int j=i+1;j<a.length-i;j++){ if(a[j]<a[min]) {
min=j;
continue; } if(a[j]>a[max]) max=j; } swap(a, i, min); swap(a, a.length-i-1, max);
}
4. 改进的冒泡排序
/** * 改进的冒泡排序 */ private static void buddle(int []a){ int high=a.length-1,low=0; while(low<high){ for(int i=low;i<high;i++){ if(a[i]>a[i+1]){ swap(a,i,i+1); } } for(int i=high;i>low;i--){ if(a[i]<a[i-1]){ swap(a,i,i-1); } } ++low; --high; } } private static void swap(int[] a, int i, int j) { if(i==j) return; a[i]+=a[j]; a[j]=a[i]-a[j]; a[i]=a[i]-a[j]; }
5.堆排序
/** 堆排序 *思想:是一种树形结构,是对直接选择排序的有效改进。 *堆的定义如下: *具有n个元素的序列(k1,k2,…,kn),当且仅当满足下面条件时称之为堆。 *Ki>=K2i,Ki>=K2i+1//Ki<=K2i,Ki<=K2i+1; *初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆, *这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。 *依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程, *一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。 */ public static void heapSort(int a[]){ for(int i=0;i<a.length;i++){ createMaxHeap(a,a.length-i);//创造最大的堆 swap(a, 0, a.length - 1 - i); } } private static void swap(int[] a, int i, int j) { if(i==j) return; a[i]+=a[j]; a[j]=a[i]-a[j]; a[i]=a[i]-a[j]; } private static void createMaxHeap(int[] a, int lastIndex) { //从最后一个节点lastIndex的父节点开始 for(int i=(lastIndex-1)/2;i>=0;i--){ int k=i;// 保存当前正在判断的节点 while(2*k+1<lastIndex){// bigIndex总是记录较大节点的值,先赋值为当前节点的左子节点的索引 int bigIndex = 2*k+1; if(bigIndex+1<lastIndex){ if (a[bigIndex] < a[bigIndex + 1]) {// 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的索引 bigIndex++; } } // 如果k节点的值小于其较大的子节点的值 if (a[k] < a[bigIndex]) { // 交换两者的值 swap(a, k, bigIndex); // 将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值 k = bigIndex; } else { break; } } } }
6.归并排序
/** * 归并排序 *思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列. */ private static void sort(int []q,int left,int right) { if(left<right){ int center=(left+right)/2; sort(q,left,center); sort(q,center+1,right); marge(q,left,center,right); } } private static void marge(int[] q, int left, int center, int right) { int third[]=new int[q.length]; int mid=center+1; int tleft=left; int tem=left; while(left<=center&&mid<=right){ if(q[left]<=q[mid]){ third[tleft++]=q[left++]; }else{ third[tleft++]=q[mid++]; } } while(mid<=right){ third[tleft++]=q[mid++]; } while(left<=center){ third[tleft++]=q[left++]; } while(tem<=right){ q[tem]=third[tem++]; } }
7. 快速排序
/** * 快速排序 * 思想:基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素, * 此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。 */ private static void quickSort(int []a,int low,int high){ if(low<high){ int mid=getMiddle(a, low, high); quickSort(a, low, mid-1); quickSort(a, mid+1, high); } } private static int getMiddle(int []a,int low,int high){ int tem=a[low]; while(low<high){ while(low<high&&a[low]<=tem){ low++; } a[low]=a[high]; while(low<high&&a[high]>=tem){ high--; } a[high]=a[low]; } a[low]=tem; return low; }
8.基数排序
/** * 基数排序 * 思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。
这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列 */ private static int[] radixSort(int[] a) { int max=a[0]; //首先确定排序趟数 for(int i=0;i<a.length-1;i++){ if(a[i]>max) max=a[i]; } int t=0; while(max>0){ max/=10; t++;//位数} //建立十个队列 ArrayList<ArrayList<Integer>> arr=new ArrayList<>(); for(int i=0;i<10;i++){ ArrayList<Integer> queue=new ArrayList<>(); arr.add(queue); } //进行t次收集和处理 for(int i=0;i<t;i++){ //分配数组元素 for(int as:a){ //得到数据的第t+1位的数 int x= as%(int)Math.pow(10, i+1)/(int)Math.pow(10, i); ArrayList<Integer> que=arr.get(x); que.add(as); arr.set(x, que); } int count=0;//元素计数器 for(int k=0;k<10;k++){ while(arr.get(k).size()>0){ ArrayList<Integer> q=arr.get(k); a[count]=q.get(0); q.remove(0); count++; }
}
} return a; }