开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第28天,[点击查看活动详情]
这三个排序属于非比较大小的 堆排序之前要把最大堆和最小堆建出来。
计数排序
CountingSort
只能对数字,或者关键字是数字的主的排序。
字符串不能。
是桶排序的一种。
将数字和角标对应起来,角标是递增的,角标对应的格子就是次数。
牺牲空间换时间。
原理
将输入的数据值转化为键存储在额外开辟的数组空间中
线性时间复杂度的排序
输入的数据必须有确定范围的整数。
index+offset=num
特点
时间复杂度:O(n+m)
空间复杂度:O(n+m)
是稳定的
代码
public class CountingSort{
public static void main(String[] args){
int[] arr = new int[20];
Random random=new Random();
for(int i =0;i<arr.length;i++){
arr[i]=random.nextInt(50);
}
countingSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void countingSort(int[] arr){
//1,获取最大值和最小值
int max=arr[0];
int min=arr[0];
for(int i=1;i<arr.length;i++){
if(arr[i]>max){
max=arr[i];
}
if(arr[i]<min){
min=arr[i];
}
}
//2,创建辅助数组
int[] temp=new int[max-min+1];
int offset=min-0;
//3,遍历原数组,将数组的个数统计在新数组中
for(int i=0;i<arr.length;i++){
temp[arr[i]-offset]++;
}
//4,遍历新数组temp,将统计结果处理
int index=0;
for(int i=0;i<temp.length;i++){
if(temp[i]!=0){
for(int j=0;j<temp[i];j++){
arr[index++]=i+offset;
}
}
}
}
}
桶排序
BucketSort
是计数排序的升级。
一堆数字针对一个角标。
利用函数的映射关系。确定映射函数
原理
假设数据均匀分布,将数据分到有限数量的桶里,每个桶再分别排序。->递归
特点
时间复杂度:O(n+m)
空间复杂度:O(n+m)
是稳定的
一个桶了就是插入排序
速度与和桶的个数有关。
public class BucketSort{
public static void main(String[] args){
int[] arr=new int[20];
Random random=new Random();
for(int i = 0;i<arr.length;i++){
arr[i]=random.nextInt(50);
}
bucketSort(arr);
System.out.println(ArraystoString(arr));
}
private static void bucketSort(int[] arr){
//获取最大值和最小值
int max=arr[0];
int min=arr[0];
for(int i=1;i<arr.length;i++){
if(arr[i]>max){
max=arr[i];
}
if(arr[i]<min){
min=arr[i]
}
}
//计算桶的数量
int bucketNum=(max-min)/arr.length+1;
//创建所有的桶
ArrayList<Integer>[] buckets=new ArrayList[bucketNum];
for(int i=0;i<buckets.length;i++){
buckets[i]=new ArrayList<>();
}
//遍历元素分别进桶
for(int i=0;i<arr.length;i++){
buckets[(arr[i]-min)/arr.length].add(arr[i]);
}
//对每一个桶进行排序
for(int i=0;i<buckets.length;i++){
buckets[i].sort(new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o1.compareTo(o2);
}
});
System.out.println(i+":"+buckets[i]);
}
//将桶中的数据放置到原数组中
int index = 0;
for(int i = 0;i<buckets.length;i++){
//while(!buckets[i].isEmpty()){
// arr[index++]=buckets[i].remove(0);
//}
for(int j=0;j<buckets[i].size();j++){
arr[index++]=buckets[i].get(j);
}
}
}
}
基数排序
RadixSort
原理
是按照低位先排序,后收集,再按高位排序,后收集。依次,->到最高位。
数论
最大最小的差值,中间过多的元素空插,会影响速率。
特点
时间复杂度:O(n+m)
空间复杂度:O(n+m)
稳定的
代码
public class RadixSort{
public stayic void main(String[] args){
int[] arr=new int[20];
Random random = new Random();
for(int i = 0;i<arr.length;i++){
arr[i]=random.nextInt(50);
}
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void radixSort(int[] arr){
//找到最大值
int max=arr[0];
for(int i=1;i<arr.length;i++){
if(arr[i]>max){
max=arr[i];
}
}
//计算位数
int radix = (max+"").length();
//创建桶
// ArrayLoopQueue循环队列
//ArrayDeque双端队列
ArrayLoopQueue<Integer>[] buckets = new ArrayLoopQueue[10];
for(int i = 0;i<buckets.length;i++){
buckets[i]=new ArrayLoopQueue<>();
}
for(int r=1;r<=radix;r++){
for(int i=0;i<arr.length;i++){
buckets[getIndex(arr[i],r)].offer(arr[i]);
}
int index=0;
for(int i=0;i<buckets.length;i++){
while(buckets[i].isEmpty()){
arr[intdex++]=buckets[i].poll();
}
}
}
}
private static int getIndex(int num,int r){
int ret=0;
for(int i =1;i<=r;i++){
ret=num%10;
num/=10;
}
return ret;
}
}
JAVA虚拟机栈会自动扩容的。
还有种猴子排序。点坐标与点坐标之间进行交换。