直接上代码,分析注释里
import java.util.Arrays;
public class Test{
public static void main(String[] agrs){
//int[] a = new int[]{6,5,7,1,3,9,8,4,2,0,10};
int[] a = new int[]{6,27,1,3,5,8,24,2,10,5,8,8,8,24};
System.out.println(Arrays.toString(a));
//quickSort(a,0,a.length-1);
//MergeSort(a,0,a.length-1);
CountSort(a);
//HeapSort(a);
//System.out.println("Counts:
"+Arrays.toString(a));
}
public static void Swap(int[] a,int x,int y){
int t = a[x];
a[x] = a[y];
a[y] = t;
}
/**
快速排序
时间复杂度与key值有关,若key是整个数组的最大或最小值,则情况最坏,时间复杂度为O(N^2),
最好的情况是类似二分,每次都从中间分,时间复杂度为O(N*logN),平均复杂度也是O(N*logN),
关于key值有三数取中优化的算法,在我的另一篇博客里有详细的代码实现
*/
//1.左右指针法
public static int parsion1(int[] a,int left,int right){
int begin = left, end = right;
int key = a[right];
while(begin<end){
while(a[begin]<=key&&begin<end){
begin++;
}
while(a[end]>=key&&begin<end){
end--;
}
Swap(a,begin,end);
}
Swap(a,begin,right);
return begin;
}
//2.挖坑法,类似于左右指针法
public static int parsion2(int[] a, int left, int right){
int begin = left, end = right;
int key = a[right];
while(begin<end){
while(begin<end&&a[begin]<=key){
begin++;
}
a[end]=a[begin];
while(begin<end&&a[end]>=key){
end--;
}
a[begin]=a[end];
}
a[begin]=key;
return begin;
}
//3.前后指针法**(难点,我到现在都不能彻底捋顺这个算法,只想说设计这个算法的人脑洞真大!!)
public static int parsion3(int[] a,int left,int right){
int cur = left;
int prev = cur-1;
while(cur<right){
if(a[cur]<=a[right]&&++prev!=cur){
Swap(a,cur,prev);
}
cur++;
}
Swap(a,++prev,right);
return prev;
}
public static void quickSort(int[] a, int left, int right){
if(right<left){
return;
}
int div = parsion3(a,left,right);
quickSort(a,left,div-1);
quickSort(a,div+1,right);
}
/**
归并排序,分治的思想
分开的复杂度为logN,合并为N,故他的复杂度始终都是O(N*logN),空间复杂度为O(N)
*/
public static void Merge(int[] a, int left, int mid, int right){
int begin1=left, end1=mid, begin2=mid+1, end2=right;
int[] tmp = new int[right-left+1];
int index=0;
while(begin1<=end1&&begin2<=end2){
if(a[begin1]<=a[begin2]){
tmp[index++]=a[begin1++];
}
else{
tmp[index++]=a[begin2++];
}
}
while(begin1<=end1){
tmp[index++]=a[begin1++];
}
while(begin2<=end2){
tmp[index++]=a[begin2++];
}
for(index=0;index<right-left+1;index++){
a[index+left]=tmp[index];
}
}
public static void MergeSort(int[] a,int left, int right){
int mid = left+((right-left)>>1);
if(left>=right)
return;
MergeSort(a,left,mid);
MergeSort(a,mid+1,right);
Merge(a,left,mid,right);
}
/**堆排序
利用向下调整,每次将最大的元素至于a[0],再将a[0]与最后一个元素交换,依次调整,即可得到有序序列
*/
public static void AdjustDown(int[] a,int i, int n){
int parent=i, child = parent*2+1;
while(child<n){
child = parent*2+1;
if(child+1<n&&a[child]<a[child+1])
child++;
if(child<n&&a[parent]<a[child]){
Swap(a,parent,child);
parent=child;
}
else
break;
}
}
public static void HeapSort(int[] a){
int i = (a.length-2)/2; //i为最后一个节点,不是叶子
for(;i>=0;--i){
AdjustDown(a,i,a.length);
}
System.out.println("1:"+Arrays.toString(a));
for(int j=a.length-1;j>0;--j){
Swap(a,0,j);
AdjustDown(a,0,j);
}
System.out.println("2:"+Arrays.toString(a));
}
/**
计数排序,将源数组以下标方式放入对应的目标数组里,如元素a[0]=5,放入目标数组的tmp[5]=1;若有两个5,则tmp[5]=2;
使用BitMap可以大大减少开销空间,但是却不能存入多个数据,不过可以使用2位,或3位来表示存入个数,
位图多用于查找某个数是否存在,而不考虑个数。
*/
public static void CountSort(int[] a){
int min=0, max=0;
for(int i=0;i<a.length;++i){
if(a[min]>a[i])
min = i;
if(a[max]<a[i])
max = i;
}
int[] tmp = new int[a[max]-a[min]+1];
for(int i=0;i<a.length;++i){
tmp[a[i]-a[min]]++;
}
for(int i=0;i<tmp.length;++i){
int j=tmp[i];
while(j!=0){
System.out.print(i+a[min]+", ");
j--;
}
}
}
}