【常用排序算法】

写在最前面

只想用其中的某个算法?

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

  • 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;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值