<span style="font-family: Arial, Helvetica, sans-serif;">import java.util.ArrayList;</span>
public class AllSorts {
public static void main(String[] args) {
int[] a = {49,38,65,97,49,76};
print(a);
//insertSort(a);
//shellSort(a);
//selectSort(a);
//bubbleSort(a);
//quickSort(a, 0, a.length-1);
//heapSort(a);
//mergerSort(a);
radixSort(a);
print(a);
}
public static void print(int[] a){
String s = "";
for(int i=0;i<a.length;i++){
s = s+a[i];
s = s+" ";
}
System.out.println(s);
}
//***************************************************************************
//插入排序(稳定排序),时间复杂度为O(n^2),空间复杂度为O(1),
public static void insertSort(int[] a){
for(int i=1;i<a.length;i++){
int j = i-1;
int temp = a[i];
for(;j>=0 && a[j]>temp;j--){
a[j+1] = a[j];
}
a[j+1] = temp;
}
}
//***************************************************************************
//希尔排序(不稳定),时间复杂度时间复杂度 平均时间 O(nlogn) 最差时间O(n^s) 1<s<2;其实就是分组的插入排序,
//由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,
//相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
public static void shellSort(int[] a){
double d1 = a.length;
int temp = 0;
while(true){
d1 = Math.ceil(d1/2);
int d = (int) d1;
for(int x=0;x<d;x++){
for(int i=x+d;i<a.length;i+=d){
int j = i-d;
temp = a[i];
for(;j>=0 && temp<a[j];j-=d){
a[j+d] = a[j];
}
a[j+d] = temp;
}
}
if(d == 1){
break;
}
}
}
//***************************************************************************
//选择排序(不稳定),时间复杂度O(n^2),空间O(1)
//就是从第二个元素开始,每次选择剩下中的最小的,和剩下中的第一个交换
//举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,
//所以选择排序不是一个稳定的排序算法
public static void selectSort(int[] a){
//position用来记录剩下元素最小值的下标
for(int i=0;i<a.length-1;i++){
int j = i+1;
//temp用来记录最小值,position用来记录最小值下标
int position = i;
int temp = a[i];
for(;j<a.length;j++){
if(temp>a[j]){
position = j;
temp = a[j];
}
}
a[position] = a[i];
a[i] = temp;
}
}
//***************************************************************************
//冒泡排序(稳定),时间O(n^2),空间O(1)
public static void bubbleSort(int[] a){
//position用来记录剩下元素最小值的下标
//temp记录最小值
for(int i=0;i<a.length-1;i++){
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] =temp;
}
}
}
}
//***************************************************************************
//快排(不稳定),时间复杂度O(nlgn),空间复杂度O(lgn)
public static void quickSort(int[] a,int left,int right){
if(left>right) return ;
//temp 就是划分左右的基准值
int temp = a[left];
int i = left;
int j = right;
while(i!=j){
//要从右向左找
while(a[j]>=temp && i<j){
j--;
}
while(a[i]<=temp && i<j){
i++;
}
if(i<j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//此时i=j,交换基准值,交换后,a[i]就是分界值,再分别对a[i]左右进行快排
a[left] = a[i];
a[i] = temp;
//对右边进行快排
quickSort(a,i+1,right);
//对左边进行快排
quickSort(a, left, i-1);
}
//***************************************************************************
//堆排序(不稳定),时间复杂度O(nlgn),空间O(1)
//堆排序是不稳定的:
//比如:3 27 36 27,建最小堆
//如果堆顶3先输出,则,第三层的27(最后一个27)跑到堆顶(即3和最后一个27交换),
//然后堆稳定,继续输出堆顶,是刚才那个27,这样说明后面的27先于第二个位置的27输出,不稳定。
public static void heapSort(int[] a){
int arrayLength = a.length;
//循环建堆,和最后一个交换,并不断缩小重建堆所需数组的大小,直到只剩下1个为止
for(int i=0;i<arrayLength-1;i++){
buildMaxHeap(a,arrayLength-1-i);
swap(a,0,arrayLength-1-i);
}
}
public static void buildMaxHeap(int[] a,int lastIndex){
for(int i=(lastIndex-1)/2;i>=0;i--){
int k = i;
while(k*2+1<=lastIndex){
int biggerIndex = 2*k+1;
if(biggerIndex+1<lastIndex){
if(a[biggerIndex]<a[biggerIndex+1]){
biggerIndex++;
}
}
if(a[k]<a[biggerIndex]){
swap(a,k,biggerIndex);
k = biggerIndex;
}else{
break;
}
}
}
}
public static void swap(int[] a,int m,int n){
int temp = a[m];
a[m] = a[n];
a[n] = temp;
}
//***************************************************************************
//归并排序(稳定的),时间复杂度为O(nlgn),空间复杂度为O(n)
public static void mergerSort(int[] a){
sort(a,0,a.length-1);
}
public static void sort(int[] a,int left,int right){
if(left<right){
int center = (left+right)/2;
sort(a,left,center);
sort(a,center+1,right);
merge(a,left,center,right);
}
}
public static void merge(int[] a,int left,int center,int right){
//合并的时候用到了临时数组,所以空间复杂度才为O(n)
int[] tmpArr = new int[a.length];
//temp用来当合并完成后,将临时数组中的元素逐个复制覆盖原数组元素,所以temp记录开始的地方
int temp = left;
int mid = center+1;
//third用来指示合并过程中,临时数组的下标
int third = left;
while(left<=center&&mid<=right){
if(a[left]<=a[mid]){
tmpArr[third++] = a[left++];
}else{
tmpArr[third++] = a[mid++];
}
}
//将某一半里面多出来的,直接复制进去。
while(left<=center){
tmpArr[third++] = a[left++];
}
while(mid<=right){
tmpArr[third++] = a[mid++];
}
//将临时数组中合并好的元素顺序再复制回(覆盖)原数组
while(temp<=right){
a[temp] = tmpArr[temp];
temp++;
}
}
//***************************************************************************
public static void radixSort(int[] a){
//首先确定要排序的趟数,即最大数的长度,例如最大数为100,就要排3趟
//先找最大数
int max = a[0];
for(int i=0;i<a.length;i++){
if(max<a[i]){
max = a[i];
}
}
//再找最大数的长度,也即需要排序的趟数
int time = 0;
while(max!=0){
max = max/10;
time++;
}
//建立10个list,即0-9
ArrayList<ArrayList<Integer>> queue = new ArrayList<ArrayList<Integer>>();
for(int i=0;i<10;i++){
ArrayList<Integer> list = new ArrayList<Integer>();
queue.add(list);
}
//进行time次重新分配排序
for(int i=0;i<time;i++){
for(int j=0;j<a.length;j++){
//得到要放入的桶号
int x = a[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i);
queue.get(x).add(a[j]);
}
int count = 0;
//再将桶中的元素重新排成队
for(int k=0;k<10;k++){
while(queue.get(k).size()>0){
a[count++] = queue.get(k).get(0);
queue.get(k).remove(0);
}
}
}
}
}