• 【常用排序算法】


    写在最前面

    只想用其中的某个算法?

    如果你只是想要对应的排序算法,可删除每个排序类的以下三处

    • extends SortTest
    • main方法
    • @Override

    比如,对于冒泡排序,删除下图中框选出来的即可单独使用
    在这里插入图片描述

    类关系图

    所有排序算法皆继承SortTest,SortTest主要用于测试算法排序的效果(正确率如何)
    在这里插入图片描述

    工具类NumberArrayUtil

    准备一个工具类,用于产生无序的数组

    • createNumberArray(int count):产生一个长度为count的数组
    • createNumberArrays():产生一定量的无序数组
    public class NumberArrayUtil {
        private static final Random RANDOM = new Random();
        /**
         * 数组的长度包含0 ~ MAX_VAL
         */
        private static final int MAX_VAL = 10;
    
        /**
         * 除了长度为0 ~ MAX_VAL长度的数组之外,再产生多少个数组
         */
        private static final int RANDOM_ARRAY_COUNT = 20;
        /**
         * 除了长度为0 ~ MAX_VAL长度的数组之外,再产生的数组最大长度
         */
        private static final int RANDOM_ARRAY_MAX_LENGTH = 100;
    
        /**
         * 产生指定长度的数组
         * @param count
         * @return
         */
        public static int[] createNumberArray(int count){
            int[] res = new int[count];
            for (int i = 0; i < res.length; i++) {
                res[i] =  RANDOM.nextInt();
            }
    
            return res;
        }
    
        /**
         * 产生一定量的随机长度的数组
         * @return
         */
        public static List<int[]> createNumberArrays(){
            List<int[]> res = new ArrayList<>();
    
            for (int i = 0; i < MAX_VAL; i++) {
                res.add(createNumberArray(i));
            }
    
            for (int i = 0; i < RANDOM_ARRAY_COUNT; i++) {
                res.add(createNumberArray(RANDOM.nextInt(RANDOM_ARRAY_MAX_LENGTH)));
            }
    
            return res;
        }
    
        /**
         * 判断两个数组的值是否相同
         * @param arr1
         * @param arr2
         * @return
         */
        public static boolean isSameArray(int[] arr1, int[] arr2){
            if (arr1.length != arr2.length){
                return false;
            }
    
            for (int i = 0; i < arr1.length; i++) {
                if (arr1[i] != arr2[i]){
                    return false;
                }
            }
    
            return true;
        }
    }
    
    

    用于测试排序的父类 SortTest

    准备一个抽象类,用于快速测试我们写的算法,是否能完成排序

    • test():子类调用,对我们实现的sort进行结果进行检验
    • sort方法是抽象方法,子类需要重写,然后调用test方法,即可完成测试
    • swap是交换两个索引处的值的方法,排序多会用到
    public abstract class SortTest {
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        public abstract int[] sort(int[] nums);
    
        /**
         * 用于检验排序结果
         */
        public void test() {
            List<int[]> numberArrays = NumberArrayUtil.createNumberArrays();
            int[] sort;
            int errorCount = 0;
            for (int[] numberArray : numberArrays) {
                int[] copy = Arrays.copyOf(numberArray, numberArray.length);
                sort = sort(Arrays.copyOf(numberArray, numberArray.length));
                Arrays.sort(copy);
                if (!NumberArrayUtil.isSameArray(sort, copy)) {
                    System.out.println(Arrays.toString(numberArray) + "排序出错,排序后的结果:\n" + Arrays.toString(sort));
                    System.out.println();
                    errorCount++;
                }
            }
            
            System.out.println("测试完成!共计:" + numberArrays.size() + "个,出错个数:" + errorCount);
        }
    
        /**
         * 交换
         *
         * @param nums
         * @param i
         * @param j
         */
        public void swap(int[] nums, int i, int j) {
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
    }
    
    

    冒泡排序

    public class BubbleSort extends SortTest{
        public static void main(String[] args) {
            new BubbleSort().test();
        }
    
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        @Override
        public int[] sort(int[] nums) {
            //排序次数
            boolean isSwap;
            for (int i = 0; i < nums.length - 1; i++) {
                //选出第i大的
                isSwap = false;
                for (int j = 0; j < nums.length - 1 - i; j++) {
                    if (nums[j] > nums[j + 1]){
                        swap(nums, j, j + 1);
                        isSwap = true;
                    }
                }
                if (!isSwap){
                    break;
                }
            }
    
            return nums;
        }
    }
    

    堆排序

    public class HeapSort extends SortTest {
        public static void main(String[] args) {
            new HeapSort().test();
        }
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        @Override
        public int[] sort(int[] nums) {
            //初始化一个大顶堆
            buildMaxHeap(nums);
    
            //堆的大小,每次减少一个
            for (int i = nums.length - 1; i > 0; i--) {
                //和最后面交换
                swap(nums, 0, i);
                //构建堆,长度-1,最后一个放最大的
                heapify(nums, 0, i);
            }
    
            return nums;
        }
    
        private void buildMaxHeap(int[] nums) {
            //从倒数第二层最后一个往前,依次构建堆
            int len = nums.length;
            for (int i = len / 2 - 1; i >= 0; i--) {
                heapify(nums, i, len);
            }
        }
    
        /**
         * 构建堆
         *
         * @param nums
         * @param index 起始索引
         * @param len   有效长度
         */
        private void heapify(int[] nums, int index, int len) {
            if (index >= nums.length){
                return;
            }
    
            int left = 2 * index + 1;
            int right = 2 * index + 2;
    
            //当前节点和其两个子节点,最大值处对应的索引
            int maxIndx = index;
    
            //是否子节点比当前节点大
            if (left < len && nums[left] > nums[maxIndx]) {
                maxIndx = left;
            }
            if (right < len && nums[right] > nums[maxIndx]) {
                maxIndx = right;
            }
    
            //和子节点交换,并对子节进行重新构建堆
            if (maxIndx != index) {
                swap(nums, index, maxIndx);
                heapify(nums, maxIndx, len);
            }
        }
    }
    
    

    插入排序

    public class InsertSort extends SortTest{
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        @Override
        public int[] sort(int[] nums) {
            //遍历
            for (int i = 1; i < nums.length; i++) {
                int tmp = nums[i];
                //如果比当前值大,都应该往后移动
                int j = i - 1;
                while (j >= 0 && nums[j] > tmp){
                    nums[j + 1] = nums[j];
                    j--;
                }
                nums[j + 1] = tmp;
            }
    
            return nums;
        }
    
        public static void main(String[] args) {
            new InsertSort().test();
        }
    }
    
    
    

    归并排序

    public class MergeSort extends SortTest {
        public static void main(String[] args) {
            new MergeSort().test();
        }
    
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        @Override
        public int[] sort(int[] nums) {
            sort(nums, 0, nums.length - 1);
            return nums;
        }
    
        private void sort(int[] nums, int left, int right) {
            //结束:
            if (right <= left) {
                return;
            }
    
            int mid = left + (right - left) / 2;
            //分成两个部分,分别排序
            sort(nums, left, mid);
            sort(nums, mid + 1, right);
    
            //归并
            int[] marge = marge(Arrays.copyOfRange(nums, left, mid + 1), Arrays.copyOfRange(nums, mid + 1, right + 1));
            System.arraycopy(marge, 0, nums, left, marge.length);
        }
    
        private int[] marge(int[] nums1, int[] nums2) {
            int[] res = new int[nums1.length + nums2.length];
            //已经添加的个数
            int index = 0;
            //两个指针
            int i = 0, j = 0;
    
            while (i < nums1.length && j < nums2.length) {
                //谁小,谁加入;//i或j增加
                if (nums1[i] > nums2[j]) {
                    res[index++] = nums2[j++];
                } else {
                    res[index++] = nums1[i++];
                }
            }
            //如果添加完了就结束
            if (index == res.length) {
                return res;
            }
            //没添加完,把某个数组剩余的部分拷贝进去
            if (i < nums1.length) {
                for (; i < nums1.length; i++) {
                    res[index++] = nums1[i];
                }
            } else {
                for (; j < nums2.length; j++) {
                    res[index++] = nums2[j];
                }
            }
    
            return res;
        }
    }
    
    

    快速排序

    public class QuickSort extends SortTest{
        public static void main(String[] args) {
            new QuickSort().test();
        }
    
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        @Override
        public int[] sort(int[] nums) {
            sort(nums, 0, nums.length - 1);
            return nums;
        }
    
        private void sort(int[] nums, int left, int right) {
            //结束:
            if (left >= right){
                return;
            }
    
            //排序
            //基准
            int val = nums[left];
            int i = left, j = right;
            while (i < j){
                //右边先移动
                while (j > i && nums[j] >= val){
                    j--;
                }
                //换到左边
                nums[i] = nums[j];
                //左边移动
                while (i < j && nums[i] <= val){
                    i++;
                }
                //换到右边
                nums[j] = nums[i];
            }
            nums[i] = val;
    
            //排左边
            sort(nums, left, i - 1);
            //排右边
            sort(nums, i + 1, right);
        }
    }
    
    

    选择排序

    public class SelectionSort extends SortTest{
    
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        @Override
        public int[] sort(int[] nums) {
            //要选n-1次
            for (int i = 0; i < nums.length - 1; i++) {
                //每次找最小的放前面
                int min = nums[i];
                int index = i;
                for (int j = i + 1; j < nums.length; j++) {
                    if (min > nums[j]){
                        min = nums[j];
                        index = j;
                    }
                }
                //交换
                swap(nums, i, index);
            }
    
            return nums;
        }
    
        public static void main(String[] args) {
            new SelectionSort().test();
        }
    }
    
    

    希尔排序

    public class ShellSort extends SortTest {
        public static void main(String[] args) {
            new ShellSort().test();
        }
    
        /**
         * 排序方法
         *
         * @param nums
         * @return
         */
        @Override
        public int[] sort(int[] nums) {
            //步长
            int step = nums.length;
    
            for (int i = step; i > 0; i /= 2) {
                //以步长为i进行快速排序
                for (int j = 0; j < step; j++) {
                    //对第j组进行排序,步长是i
                    sort(nums, j, i);
                }
            }
    
            return nums;
        }
    
        /**
         * 希尔排序,对第startIndex组进行排序
         *
         * @param nums
         * @param startIndex 起始索引
         * @param step       步长
         */
        private void sort(int[] nums, int startIndex, int step) {
            for (int i = startIndex + step; i < nums.length; i += step) {
                int tmp = nums[i];
                //一直向前找,找到一个比当前值小的值
                int j = i - step;
                while (j >= 0 && nums[j] > tmp) {
                    nums[j + step] = nums[j];
                    j -= step;
                }
    
                //插入在其后面
                nums[j + step] = tmp;
            }
        }
    }
    
    
  • 相关阅读:
    iPhone相机参数设置,苹果原相机也能拍出大片感
    英语考试的作文模板
    做公众号1年啦
    常见故障及其解决方法
    力扣:171. Excel 表列序号(Python3)
    vivo手机如何隐藏应用 vivo手机隐藏应用方法
    Golang goroutine 进程、线程、并发、并行
    golang 协程并发代码 demo
    Buffer I/0 error on dev dm-2, logical block 138823488, async page read CCSSDN
    【计算机视觉】上采样和下采样
  • 原文地址:https://blog.csdn.net/m0_55155505/article/details/127095703