直接上代码


import java.util.ArrayList;
import java.util.Collections;

public class MySort {

    public static void main(String[] args) {
        MySort mySort = new MySort();
        int[] arr = new int[]{5, 6, 1, 2, 3, 4, 11, 12, 32, 55, 122, 21};
//        mySort.bubbleSort(arr);
//        mySort.selectionSort(arr);
//        mySort.insertionSort(arr);
//        mySort.shellSort(arr);
//        mySort.quickSort(arr);
//        mySort.mergeSort(arr);
//        mySort.heapSort(arr);
//        mySort.countSort(arr);
//        mySort.bucketSort(arr);
//        mySort.radixSort(arr);
//        System.out.println(Arrays.toString(arr));
//        Arrays.sort(arr);
//        System.out.println(mySort.binarySearch(arr, 11, 0, arr.length - 1) == Arrays.binarySearch(arr, 11));
    }

    /**
     * 交换数组中的元素
     *
     * @param nums 数组
     * @param i    交换的第一个数字
     * @param j    交换的第二个数字
     */
    public void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    /**
     * 冒泡排序
     * <p>
     * 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
     * <p>
     * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
     * <p>
     * 针对所有的元素重复以上的步骤,除了最后一个。
     * <p>
     * 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
     *
     * @param nums 排序数组
     */
    public void bubbleSort(int[] nums) {
        for (int i = 0; i < nums.length - 1; i++) {
            //这里有一个优化的点是,每冒泡一次,最大的数就会排到后面去,那么最后面的数就不用比较,必定是有序的
            for (int j = 0; j < nums.length - i - 1; j++) {
                if (nums[j] > nums[j + 1]) {
                    swap(nums, j, j + 1);
                }
            }
        }
    }

    /**
     * 选择排序
     * <p>
     * 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
     * <p>
     * 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
     * <p>
     * 重复第二步,直到所有元素均排序完毕。
     *
     * @param nums 排序数组
     */
    public void selectionSort(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            int minIndex = i;
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[minIndex] > nums[j]) {
                    minIndex = j;
                }
            }
            swap(nums, i, minIndex);
        }
    }

    /**
     * 插入排序
     * <p>
     * **不断地向前比较/交换,插入到合适的位置**
     * <p>
     * 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
     * <p>
     * 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
     *
     * @param nums 排序数组
     */
    public void insertionSort(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            int index = i;
            int num = nums[index];
            while (index > 0 && num < nums[index - 1]) {
                nums[index] = nums[index - 1];
                index--;
            }
            nums[index] = num;
        }
    }

    /**
     * 希尔排序
     * <p>
     * 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
     * <p>
     * 按增量序列个数 k,对序列进行 k 趟排序;
     * <p>
     * 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
     *
     * @param nums 排序数组
     */
    public void shellSort(int[] nums) {
        int len = nums.length;
        for (int step = len / 2; step >= 1; step /= 2) {
            for (int i = step; i < len; i++) {
                int num = nums[i];
                int j = i - step;
                while (j >= 0 && nums[j] > num) {
                    nums[j + step] = nums[j];
                    j -= step;
                }
                nums[j + step] = num;
            }
        }
    }

    /**
     * 归并排序
     * <p>
     * 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
     * <p>
     * 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
     * <p>
     * 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
     * <p>
     * 重复步骤 3 直到某一指针达到序列尾;
     * <p>
     * 将另一序列剩下的所有元素直接复制到合并序列尾。
     *
     * @param nums 排序数组
     */
    public void mergeSort(int[] nums) {
        myMergeSort(nums, new int[nums.length], 0, nums.length - 1);
    }

    /**
     * 归并排序
     *
     * @param nums  排序数组
     * @param temp  临时数组,临时存放变量
     * @param left  左边界,闭区间
     * @param right 有边界,闭区间
     */
    public void myMergeSort(int[] nums, int[] temp, int left, int right) {
        if (left >= right) {
            return;
        }
        int mid = (left + right) / 2;
        myMergeSort(nums, temp, left, mid);
        myMergeSort(nums, temp, mid + 1, right);
        int index = 0;
        int l = left;
        int r = mid + 1;
        while (l <= mid && r <= right) {
            if (nums[l] <= nums[r]) {
                temp[index++] = nums[l++];
            } else {
                temp[index++] = nums[r++];
            }
        }
        while (l <= mid) {
            temp[index++] = nums[l++];
        }
        while (r <= right) {
            temp[index++] = nums[r++];
        }
        for (int i = left, j = 0; i <= right; i++, j++) {
            nums[i] = temp[j];
        }
    }

    /**
     * 快速排序
     * <p>
     * 从数列中挑出一个元素,称为 "基准"(pivot);
     * <p>
     * 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
     * <p>
     * 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
     *
     * @param nums 排序数组
     */
    public void quickSort(int[] nums) {
        myQuickSort(nums, 0, nums.length - 1);
    }

    /**
     * 快速排序
     *
     * @param nums  排序数组
     * @param left  排序左边界
     * @param right 排序右边界
     */
    public void myQuickSort(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int l = left;
        int r = right;
        while (l < r) {
            while (l < r && nums[left] <= nums[r]) {
                r--;
            }
            while (l < r && nums[left] >= nums[l]) {
                l++;
            }
            swap(nums, l, r);
        }
        swap(nums, l, left);
        myQuickSort(nums, left, l - 1);
        myQuickSort(nums, l + 1, right);
    }

    /**
     * 堆排序
     * <p>
     * 堆排序的思想就是先将待排序的序列建成大根堆,使得每个父节点的元素大于等于它的子节点。
     * <p>
     * 此时整个序列最大值即为堆顶元素,我们将其与末尾元素交换,使末尾元素为最大值。
     * <p>
     * 然后再调整堆顶元素使得剩下的 n-1 个元素仍为大根堆,再重复执行以上操作我们即能得到一个有序的序列。
     *
     * @param nums 排序数组
     */
    public void heapSort(int[] nums) {
        int len = nums.length - 1;
        buildMaxHeap(nums, len);
        for (int i = len; i >= 1; i--) {
            swap(nums, 0, len);
            maxHeapify(nums, 0, --len);
        }
    }

    /*
      初始化堆
    */
    public void buildMaxHeap(int[] nums, int len) {
        //数组倒数第二层,向上堆化
        for (int i = len / 2; i >= 0; i--) {
            maxHeapify(nums, i, len);
        }
    }

    public void maxHeapify(int[] nums, int i, int len) {
        //当子节点小于数组长度时进行排序
        if (i >= len) {
            return;
        }
        int lson = i * 2 + 1;
        int rson = i * 2 + 2;
        int large;
        //左右父节点中取最大
        if (lson <= len && nums[lson] > nums[i]) {
            large = lson;
        } else {
            large = i;
        }
        if (rson <= len && nums[rson] > nums[large]) {
            large = rson;
        }
        if (large != i) {
            swap(nums, i, large);
            maxHeapify(nums, large, len);
        }
    }

    /**
     * 计数排序
     * <p>
     * 找出待排序的数组中最大和最小的元素
     * <p>
     * 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
     * <p>
     * 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
     * <p>
     * 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
     *
     * @param nums 排序数组
     */
    public void countSort(int[] nums) {
        int min = 0;
        int max = 0;
        for (int num : nums) {
            min = Math.min(min, num);
            max = Math.max(max, num);
        }
        int[] arr = new int[max - min + 1];
        for (int num : nums) {
            arr[num - min]++;
        }
        int index = 0;
        for (int i = 0; i < arr.length; i++) {
            while (arr[i] > 0) {
                nums[index++] = i + min;
                arr[i]--;
            }
        }
    }

    /**
     * 桶排序
     * <p>
     * 计数排序的升级版,基数排序的桶的间隔为1,这里桶的间隔扩大,适用于给数据分间隔、大数据区间查找
     *
     * @param nums 排序数组
     */
    public void bucketSort(int[] nums) {
        int min = 0;
        int max = 0;
        for (int num : nums) {
            min = Math.min(min, num);
            max = Math.max(max, num);
        }
        //默认5个桶
        int BUCKET_SIZE = 5;
        int BUCKET_GAP = max / BUCKET_SIZE + 1;
        ArrayList<Integer>[] lists = new ArrayList[BUCKET_SIZE];
        for (int num : nums) {
            int bucketIndex = num / BUCKET_GAP;
            if (lists[bucketIndex] == null) {
                lists[bucketIndex] = new ArrayList<>();
            }
            lists[bucketIndex].add(num);
        }
        int index = 0;
        for (ArrayList<Integer> list : lists) {
            if (list != null) {
                Collections.sort(list);
                for (Integer integer : list) {
                    nums[index++] = integer;
                }
            }
        }
    }

    /**
     * 基数排序
     * <p>
     * **从个位数一直排到最高位**
     * <p>
     * 将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。
     * <p>
     * 然后,从最低位开始,依次进行一次排序。
     * <p>
     * 这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
     *
     * @param nums 排序数组
     */
    public void radixSort(int[] nums) {
        int k = 0;
        int n = 1;
        int m = 1; //控制键值排序依据在哪一位
        int max = 0;
        for (int num : nums) {
            max = Math.max(max, num);
        }
        int d = 1;
        while (max > 0) {
            max /= 10;
            if (max > 0) {
                d++;
            }
        }
        int[][] temp = new int[10][nums.length]; //数组的第一维表示可能的余数0-9
        int[] order = new int[10]; //数组order[i]用来表示该位是i的数的个数
        while (m <= d) {
            for (int num : nums) {
                int lsd = ((num / n) % 10);
                temp[lsd][order[lsd]] = num;
                order[lsd]++;
            }
            for (int i = 0; i < 10; i++) {
                if (order[i] != 0)
                    for (int j = 0; j < order[i]; j++) {
                        nums[k] = temp[i][j];
                        k++;
                    }
                order[i] = 0;
            }
            n *= 10;
            k = 0;
            m++;
        }
    }

    /**
     * 二分查找
     *
     * @param nums   排序后的数组
     * @param target 目标值
     * @return 找到目标值就返回数组,否则返回-1
     */
    public int binarySearch(int[] nums, int target, int left, int right) {
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }
}