1、计数排序
1、找出待排序的数组中最大和最小的元素
2、统计数组中每个值为 i的元素出现的次数,存入数组 C 的第i项
3、 对所有的计数累加 (从C中的第一个元素开始,每一项和前一项相加)
4、 反向填充目标数组:将每个元素 i放在新数组的第 C[i]项,每放一个元素就将 C[i]减去1
-维基百科
import java.util.Arrays;
/*A:待排序数组 B:辅助数组 C新数组
* ①找出数组A中的最大值和最小值
* ②遍历每个元素,把值为X的元素出现的次数,存到B[X]
* ③从第一项开始,分别计算B[X]与B[X-1]的和,并存到B[X]中(得到X元素前有多少个元素)
* ④依次将B数组中i放到C[i],每放一次,B[i]--
* */
public class CountingSort {
public static void main(String[] args) {
System.out.println("未排序前的A:");
int[]A={2,10,28,19,30,30,28,1,0,29,10,20,20,10,19,29};
System.out.println(Arrays.toString(A));
System.out.println("使用计数排序后的A:");
System.out.println(Arrays.toString(countingsort(A)));
}
public static int[] countingsort(int []A){
//①找最大值和最小值
int max=Integer.MIN_VALUE;
int min=Integer.MAX_VALUE;
for (int i = 0; i <A.length ; i++) {
min=Math.min(min,A[i]);
max=Math.max(max,A[i]);
}
//②遍历每个元素,把值为X的元素出现的次数,存到B[X]
int[]B=new int[max-min+1];
for (int i = 0; i <A.length ; i++) {
B[A[i]]++;
}
//③将数组 B中的元素i,放到新数组C上,每放一次B[i]--
int [] C=new int[A.length];
int j=0;
for (int i = 0; i < B.length; i++) {
while (B[i]!=0){
C[j++]=i;
B[i]--;
}
}
return C;
}
}
时间复杂度:
当输入的元素是 n个 0 到 k 之间的整数时,它的运行时间是 O(n+k)
2、桶排序
①找到待排序的数组A的min和max
②桶的数量(A.length)
③遍历数组A,把每个元素放到对应的桶中
④对每个桶的内部进行排序
⑤遍历每个桶
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
/*
①找到待排序的数组A的min和max
②桶的数量(max-min)/(A.length)+1
③遍历数组A,把每个元素放到对应的桶中
④对每个桶的内部进行排序
⑤遍历每个桶
*/
public class BucketSorting {
public static void main(String[] args) {
System.out.println("未排序前的A:");
int[]A={0,30,0,28,19,30,30,28,1,0,29,10,20,20,10,19,29};
System.out.println(Arrays.toString(A));
System.out.println("使用桶排序后的A:");
System.out.println(Arrays.toString(bucketsort(A)));
}
private static int[] bucketsort(int[] A) {
int max=Integer.MIN_VALUE;
int min=Integer.MAX_VALUE;
//找最值
for (int i = 0; i <A.length ; i++) {
max=Math.max(max,A[i]);
min=Math.min(min,A[i]);
}
//计算桶的数目
int buckets=A.length;
//把A中的元素分别放到对应的桶中,用ArrayList来实现桶
ArrayList<ArrayList<Integer>> bucketArray=new ArrayList<>(buckets);
for (int i = 0; i <buckets ; i++) {
bucketArray.add(new ArrayList<Integer>());
}
//遍历元素,并放到桶里面
for (int i = 0; i <A.length ; i++) {
int bucketsNum=getBucket(A[i],buckets,min,max);
bucketArray.get(bucketsNum).add(A[i]);
}
//对每个桶内部进行排序
for(int i = 0; i < bucketArray.size(); i++){
Collections.sort(bucketArray.get(i));
}
System.out.println(bucketArray.toString());
//合并每个桶
int count=0;
int[] result=new int[A.length];
for(int i = 0; i < bucketArray.size(); i++){
for (int j=0;j<bucketArray.get(i).size();j++){
result[count]=bucketArray.get(i).get(j);
count++;
}
}
return result;
}
public static int getBucket(int num,int buckets,int min,int max){
return (int)((num-min)*(buckets-1)/(max-min));
//(num-min)/(max-min)表示这个数在(max-min)所占比重,
//再乘以桶的个数就得到对应桶的编号
}
时间复杂度:
当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间O(n)
3、基数排序
基数排序(英语:Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
基数排序的核心思想就是:按照从低位到高位依次比较排序
算法如下:
输入:待排序的数组A
①创建10个桶,编号分别0,1,2,3…9,每个桶可容纳的元素为A.length个元素
int[ ] [ ] bucket=new int [10 ][A.length ];
②依次取A中元素的个位进行排序,覆盖原数组
取A中元素的十位进行排序
取A中元素的百位进行排序
.
.
.
代码
import java.util.Arrays;
public class RadixSorting {
public static void radixsorting(int[] A){
//创建10个桶,每个桶可以放A.length个元素
int[][] bucket=new int[10][A.length];
//找出最大值和最小值,并确定有几位(也可以手动给出)
int min=Integer.MAX_VALUE;
int max =Integer.MIN_VALUE;
for (int i = 0; i <A.length ; i++) {
max=Math.max(A[i], max);
min=Math.min(A[i],min);
}
int maxcopy=max;
int digits=0;
while(maxcopy!=0){
maxcopy=maxcopy/10;
digits++;
}
//控制分离数字的每一位
int split= 1;
for (int i = 1; i <digits+1 ; i++) {
int[] bucketmessage=new int[10];//用来记录每个桶内有多少个数字
//用num来分离,数字的每一位
int bnum=0;
for (int j = 0; j < A.length; j++) {
bnum=(A[j]/split)%10;
bucket[bnum][bucketmessage[bnum]]=A[j];
bucketmessage[bnum]++;
}
//把排过序的桶里面的数据取出来覆盖,A
int count1=0;
int count2=0;
for (int j = 0; j < 10; j++) {
while (bucketmessage[j]!=0){
A[count1++]=bucket[j][count2++];
bucketmessage[j]--;
}
count2=0;
}
split=split*10;
}
}
public static void main(String[] args) {
int [] A={10,123,348,123,442,567,89,38,109,108,75,118,234,289,530};
System.out.println("未排序前的A数组");
System.out.println(Arrays.toString(A));
radixsorting(A);
System.out.println("排序后的A数组");
System.out.println(Arrays.toString(A));
}
}
#4、练习:桶排序的扩展应用
给定一个数组, 求如果排序之后, 相邻两数的最大差值, 要求时 间复杂度O(N), 且要求不能用非基于比较的排序。
分析:
①待排序数组A有n个元素,那么就构建n+1个桶,那么肯定会有空桶存在,由此可以推断出,最大差值不在桶的内部,可定在相邻的桶之间;
②构建三个数组
·int [ ] hasnum : 用来记录桶中是否含有元素;
·int [ ] mins :用来桶中的最小值
·int [ ] maxs :用来桶中的最大值
③从编号为1的桶,依次取桶最小值-前一个桶的最大值,从而得到最大差值。
代码如下:
import java.util.Arrays;
public class exercise_maxGap {
public static int maxgap(int[]A){
int[] bucket=new int[A.length+1];
int max=Integer.MIN_VALUE;
int min=Integer.MAX_VALUE;
for (int i = 0; i <A.length ; i++) {
min=Math.min(min,A[i]);
max=Math.max(max,A[i]);
}
int getBnum=0;
boolean[]hasnum= new boolean[A.length + 1];
int[]mins = new int[A.length+1];
int[]maxs = new int[A.length+1];
//把数组中的每个元素都放到桶中,并记录桶内的最大值和最小值
for (int i = 0; i <A.length ; i++) {
getBnum=(int)((A[i]-min)*(A.length))/(max-min);
mins[getBnum]=hasnum[getBnum] ? Math.min(A[i],mins[getBnum]):A[i];
maxs[getBnum]=hasnum[getBnum] ? Math.max(A[i],maxs[getBnum]):A[i];
hasnum[getBnum]=true;
}
//开始找最大差值了
int result=0;
int lastmax=maxs[0];
for (int i = 1; i <A.length ; i++) {
if (hasnum[i]==true){
result=Math.max(result,mins[i]-lastmax);
lastmax=maxs[i];
}
}
return result;
}
public static void main(String[] args) {
int [] A={10,123,348,123,442,567,89,38,109,108,75,118,234,289,530};
System.out.println("A数组:");
System.out.println(Arrays.toString(A));
System.out.println("相邻的数字间最大的差值为:");
System.out.println(maxgap(A));
}
}