[卧龙凤雏]睡眠排序和随机排序

注意:以下排序不要用于生产环境

1. 睡眠排序

1.1 简介

睡眠排序(Sleep Sort)是一个非常有趣且奇特的排序算法,第一次看到就觉得惊为天人。睡眠排序并不是一个实际可用于大规模数据排序的算法,而更像是一种编程趣味或者计算机科学的玩笑。原理基于多线程和睡眠的概念,不是传统的比较排序算法。

睡眠排序的主要思想是将待排序的一组整数分配给多个线程,每个线程负责处理一个整数,它们根据整数的值来设置睡眠时间。整数越小,睡眠时间越短,整数越大,睡眠时间越长。当所有线程都完成睡眠后,它们按照睡眠时间的长短排列,从而实现排序。

主要思路:

  1. 创建一个数组,其中包含待排序的整数。
  2. 对于数组中的每个整数,创建一个线程来处理它。
  3. 每个线程计算自己要休眠的时间,通常是整数值乘以一个常数,以确保休眠时间的差异。
  4. 所有线程同时开始休眠。
  5. 当一个线程醒来后,它将自己的整数放入一个结果数组中。
  6. 重复步骤4和步骤5,直到所有线程都完成。
  7. 最后,结果数组中的整数按照休眠时间的升序排列,即得到排序后的结果。

限制:

  1. 不稳定性:由于线程的调度和休眠不稳定,这个算法不保证排序的稳定性。
  2. 效率问题:算法的效率极低,它的时间复杂度可以达到O(n^2)级别,这在实际应用中不可接受。
  3. 负整数问题:如果待排序数组包含负整数,那么这个算法会在负整数的线程上休眠很长时间,导致等待时间非常长。

1.2 代码实现

java 复制代码
import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class SleepSort {
    public static void main(String[] args) throws InterruptedException {

        int count = 100;

        int[] nums = new int[count];
        Random random = new Random();
        // 限制程序不要过早中断
        CountDownLatch countDownLatch = new CountDownLatch(count);
        // 随机 100 个 1 - (10 * count) 的数
        for (int i = 0; i < count; i++) {
            nums[i] = random.nextInt(1, 10 * count);
        }
        // 开启虚拟线程,延迟一定时间后打印数字
        for (int i = 0; i < count; i++) {
            int num = nums[i];
            Thread.startVirtualThread(() -> {
                try {
                    Thread.sleep(10L * num);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(num);
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
    }
}

2. 随机排序(猴子排序)

2.1 简介

随机排序,也称为乱序排序(Random Sort)、洗牌排序(Shuffle Sort)或猴子排序(Monkey Sort),特点是将待排序的元素随机排列。

主要思路:

  1. 输入待排序的元素组成的列表或数组。
  2. 对于列表中的每个元素,生成一个随机数或随机权重,并将元素与其对应的随机数关联。
  3. 根据随机数对元素进行排序。这通常可以使用标准的排序算法,如快速排序或归并排序,但比较的标准是元素的随机数而不是元素本身的值。
  4. 完成排序后,元素就会以随机的顺序排列。

限制:

  1. 随机性:由于随机数的引入,每次随机排序的结果都会不同,即使相同的输入数据也会产生不同的输出。
  2. 不稳定性:随机排序通常不保证排序的稳定性,因为它完全依赖于随机数。
  3. 低效性:随机排序的时间复杂度通常较高,取决于用于排序的具体算法。这远不如许多其他排序算法,因此不适合大规模数据集的排序任务。

2.2 代码实现

java 复制代码
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class RandomSort {
    public static void main(String[] args) throws InterruptedException {
        // 这个数建议不要太大,不然要随机好久
        int count = 5;
        Random random = new Random();
        // 限制主线程不要退出
        CountDownLatch countDownLatch = new CountDownLatch(1);
        int[] nums = new int[count];
        for (int i = 0; i < count; i++) {
            nums[i] = random.nextInt(10);
        }
        int[] sortedNums = Arrays.copyOf(nums, nums.length);
        // 这里偷懒直接用sort方法,然后在下面直接判断
        Arrays.sort(sortedNums);
        long startTime = System.currentTimeMillis();
        // 这里开一百万个虚拟线程随机
        for (int i = 0; i < 1000000; i++) {
            Thread.startVirtualThread(() -> {
                while (countDownLatch.getCount() > 0){
                    int[] tmp = new int[count];
                    for (int j = 0; j < count; j++) {
                        tmp[j] = random.nextInt(10);
                    }
                    // 可以打印中间过程的输出
                    // System.out.println(Arrays.toString(tmp));
                    if (Arrays.equals(sortedNums, tmp)){
                        System.out.println("排序完毕:未排序数据" + Arrays.toString(nums));
                        System.out.println("排序完毕:已排序数据" + Arrays.toString(tmp));
                        countDownLatch.countDown();
                        break;
                    }
                }
            });
        }
        countDownLatch.await();
        // 计算总时间
        System.out.println(System.currentTimeMillis() - startTime);
    }
}

3. 总结

这两个排序算法可以说是排序算法界的卧龙凤雏,建议大家还是不要在生产环境使用。