1.计数排序
核心:将输入的数据转化为健存储在额外开辟的数组空间中,输入的数据必须是确定范围的整数。
时间复杂度:O(N+M)
空间复杂度:O(N+M)
稳定性:稳定;
//:主要是针对数字进行排序,要是字符串就不是那么合适了;
公式:offset(偏移量)
offset = num - index; // : 先找到最大值和最小值,然后计算偏移量
index + offset = num;
num - offset = index;
// 总的来说就是创建一个数组,里面存放的是数字出现的次数;如图所示:
代码实现:
public class CountSort {
//计数排序
public static void main(String[] args) {
int[] arr = new int[10];
Random random = new Random();
for (int i = 0; i < arr.length - 1; i++){
arr[i] = random.nextInt(50);
}
countSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void countSort(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; i <temp[i]; j++){
arr[index++] = i + offset;
}
}
}
}
}
缺点:如果是一组只有最大值和最小值的数,那除了头尾角标,中间部分都浪费了。
2.桶排序
定义:桶排序是计数排序的优化,他利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定,桶排序(Bucket sort)的工作原理:假设输入数据从均匀分布,将数据分到有限数量的桶里,每个桶里分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。
注解:将上面的数字大致分为四个区间,[1,10],[11,20],[21,30],[31,40]这四个区间,下面的0,1,2,3位角标,
注解:多个数字共享一个角标, 对于每一个桶中,进行排序,这种思想类似于分治,大问题分为小问题,把分解的问题解决,在进行合并。代码如下:
分桶的最好方法就是:(max - min) / arr.length + 1 //数值上的差距再除以数组长度加一;
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 - 1; i++){
arr[i] = random.nextInt(50);
}
bucketSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void bucketSort(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 nucketNum = (max - min) / arr.length + 1;
//3.创建所有的桶,创建一个ArrayList的一维数组
ArrayList<Integer>[] buckets = new ArrayList[nucketNum];
for (int i = 0; i < buckets.length; i++) {
buckets[i] = new ArrayList<>();
}
//4.遍历元素,分别进桶
for (int i = 0; i < arr.length; i++) {
buckets[(arr[i] - min) / arr.length].add(arr[i]);
}
//5.对每一个桶进行排序
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(buckets[i]);
}
//6.将桶中的数据放置到原数组中
int index = 0;
for (int i = 0; i < buckets.length; i++){
for (int j = 0; j < buckets[i].size(); j++){
arr[index++] = buckets[i].get(j);
}
}
}
}
3.基数排序
定义:基数排序是按照低位排序,然后收集;再按照高位排序,然后再收集;依次类推,知道最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。
注释:和桶排序不同的是,基数排序只有十个桶,如下图:
解析:有一串数字,下面有十个桶,分别从数字的各位开始让数字分到对应个位的桶中,上图为个位分配情况,之后按照先后顺序,就是先进桶里的先出去,再把所有的数字拿出,得到以下结果:
120 , 12 , 32, 32 ,232 , 345, 25 ,67 , 8 , 9
再按照十位上的数字进行排序,如下所示:
再按照从底向上取出,结果为:
8 , 9 , 12 , 120 , 25 , 32 , 32 , 232 , 345 , 67
再按百位进行分配进桶,如图所示:
此时,不难看出,再次从底向上拿出之后,数字就已经是有序的,结果如下:
8 , 9 , 12 , 25 , 32, 32, 67 , 120 ,232 , 345
// 知道最大值,然后看最大值有几位,最高位是多少就走多少轮次;上面最大值为345,最多三位,所以一共走三轮;
// 每轮结束后,都要放回到原数组中,然后再进行下一轮;
代码实现:
ublic class RadixSort {
public static void main(String[] args) {
int[] arr = new int[20];
Random random = new Random();
for (int i = 0; i < arr.length - 1; i++){
arr[i] = random.nextInt(50);
}
radixsort(arr);
System.out.println(Arrays.toString(arr));
}
private static void radixsort(int[] arr) {
//1.先找到一个最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++){
if (arr[i] > max){
max = arr[i];
}
}
//2.计算位数
int radix = (max + "").length();
//3.创建桶,十个桶
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[index++] = 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;
}
}