排序:冒泡、插入、选择、快速、归并

冒泡排序贪心的,每次能在余下部分得到一个最值的位置。一轮冒泡可能多次交换位置。贪心是指每一步能得到最终解的一部分。

插入排序是依次将数值插入到有序部分,寻找插入位置的方式如果是一个一个比较,是直接插入排序,如果是二分查找方式,是二分插入排序。依次增加元素,得到局部解,最终得到整体解,是动态规划的思想。

选择排序是和冒泡一样是贪心的,每次能得到一个最值的位置。但是是每一轮找到余下部分最值的位置,然后和一侧交换位置,每一轮只交换一次位置。

快速排序是JDK默认的排序方式,是平均最快的。使用对撞指针将数值插入到两侧都比之大或者小的位置。是贪心的,每次能找到一个数值的位置。是分治的,在两侧部分递归相同操作。

归并排序是递归分解后递归拼接有序部分,平均速度仅次于快速排序。是分治的。

1.0 十大经典排序算法 | 菜鸟教程

package sort;

public class SortTest {

    /**
     * 方式 是否稳定(等值是否换相对位置)	时间复杂度	是否原地排序(不用新增数组临时存储有序元素)
     * 冒泡	Y	O(n^2)	Y
     * 插入	Y	O(n^2)	Y       二分插入排序虽然查找快,但和直接插入排序一样还是得后移相同大小
     * 选择	N	O(n^2)	Y
     * 快速	N	O(nlogn)	Y
     * 归并	Y	O(nlogn)	N
     * 堆
     * @param args
     */
    public static void main(String[] args) {
        // 快:quickSort > mergeSort  >>> insertSort >> selectSort >>> bubbleSort
        int[] array = {3, 5, 1, 2, 6};
//        bubbleSort(array);
        insertSort1(array);
//        selectSort(array);
//        quickSort(array);
//        mergeSort(array);
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }

    /**
     * 冒泡排序
     *
     * @param array
     */
    private static void bubbleSort(int[] array) {
        int n = array.length;
        // n - 1个值到达右侧
        // i:冒泡的轮数索引,选择最值的轮数索引
        for (int i = 0; i < n - 1; i++) {
            // 比较n - 1 - j次;i = 0时,比较n - 1次
            // j:用于比较的两个元素中左侧元素的索引
            for (int j = 0; j < n - 1 - i; j++) {
                // > 从小到大:将最大值移动到右侧,然后将次大值移动到最大值左侧...
                // < 从大到小:将最小值移动到右侧,然后将次小值移动到最小值左侧...
                if (array[j] < array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }

    /**
     * 直接插入排序
     *
     * @param array
     */
    private static void insertSort(int[] array) {
        int length = array.length;
        // 从第二个值开始,将值插入到应该在的位置,每次插入时前面的已经是有序的
        // 插入时一个一个比较是直接插入排序,二分查找是二分插入排序
        // i:用于插入的元素的索引
        for (int i = 1; i < length; i++) {
            int waitInsertValue = array[i];
            // j:用于和插入元素比较的元素的索引
            int j;
            // waitInsertValue < array[j]
            // < 从小到大:左侧选择小的位置插入
            // > 从大到小:左侧选择大的位置插入
            for (j = i - 1;j >= 0 && waitInsertValue > array[j];j--) {
                // 原始位置的值后移,空出最终插入的位置
                array[j + 1] = array[j];
            }

            array[j + 1] = waitInsertValue;
        }
    }

    /**
     * 二分插入排序
     *
     * @param array
     */
    private static void insertSort1(int[] array) {
        int n = array.length;
        for(int i = 1;i < n;i++){
            int waitInsertValue = array[i];
            int waitInsertIndex;
            int left = 0;
            int right = i - 1;
            while(left < right){
                int mid = (left + right) / 2;
                if(waitInsertValue < array[mid]){
                    right = mid - 1;
                } else if(array[mid] < waitInsertValue){
                    left = mid + 1;
                } else {
                    // 找到插入位置
                    // waitInsertIndex = left + 1;
                    break;
                }
            }

            // waitInsertValue == array[mid;或者插入两个元素组成的有序数组时退出,此时left == right,要插入的位置在left或者left + 1
            if(waitInsertValue < array[left]){
                waitInsertIndex = left;
            } else {
                waitInsertIndex = left + 1;
            }

            for(int j = i - 1;j >= waitInsertIndex;j--){
                array[j + 1] = array[j];
            }

            array[waitInsertIndex] = waitInsertValue;
        }
    }

    /**
     * 选择排序 最值放左侧
     * 选择排序不稳定,比如6,6,2,从小到大排序,第一个6会和2互换位置
     */
    private static void selectSort(int[] array) {
        int length = array.length;
        // 选择最值的轮数索引
        for (int i = 0; i < length - 1; i++) {
            // 默认最值索引
            int needIndex = i;
            for (int j = i + 1; j < length; j++) {
                // < 从小到大:选择最小的放到左侧
                // > 从大到小:选择最大的放到左侧
                if (array[j] > array[needIndex]) {
                    needIndex = j;
                }
            }

            if (needIndex != i) {
                int temp = array[i];
                array[i] = array[needIndex];
                array[needIndex] = temp;
            }
        }
    }

    /**
     * 选择排序 最值放右侧
     */
    private static void selectSort1(int[] array) {
        int n = array.length;
        for(int i = 0;i < n - 1;i++){
            // 默认最值索引
            int needIndex = n - 1 - i;
            for(int j = 0;j <= n - 1 - i;j++){
                // > 从小到大:选择最大的放到右侧
                // < 从大到小:选择最大的放到右侧
                if(array[j] > array[needIndex]){
                    needIndex = j;
                }
            }

            if(needIndex != n - 1 - i){
                int temp = array[n - 1 - i];
                array[n - 1 - i] = array[needIndex];
                array[needIndex] =  temp;
            }
        }
    }

    /**
     * 快速排序
     * 将第一个放到中间,并使左侧都比此值小,右侧都比此值大
     * 分治:左侧和右侧执行相同操作
     * 不稳定:等值元素会交换相对位置,如5,3,3,从小到大排序,因为对撞指针的方式右侧的3会到达5的位置,也就是左侧3的左侧
     * @param array
     */
    private static void quickSort(int[] array) {
        quickSort(array, 0, array.length - 1);
    }

    private static void quickSort(int[] array, int leftIndex, int rightIndex) {
        // key放在数组最右侧时,之后的递归,对于左侧部分,leftIndex == rightIndex,对于右侧leftIndex < rightIndex
        if (leftIndex >= rightIndex) {
            return;
        }

        int currentLeftIndex = leftIndex;
        int currentRightIndex = rightIndex;
        int key = array[currentLeftIndex];
        // 对撞指针,从小到大时:比key小的移动到左侧,比key大的移动到右侧,key放到左右指针对撞的位置
        while (currentLeftIndex < currentRightIndex) {
            // >= 从小到大
            // <= 从大到小
            while (currentLeftIndex < currentRightIndex && array[currentRightIndex] > key) {
                currentRightIndex--;
            }

            array[currentLeftIndex] = array[currentRightIndex];

            // <= 从小到大
            // >= 从大到小
            while (currentLeftIndex < currentRightIndex && array[currentLeftIndex] < key) {
                currentLeftIndex++;
            }

            array[currentRightIndex] = array[currentLeftIndex];
        }

        array[currentLeftIndex] = key; // currentLeftIndex == currentRightIndex
        quickSort(array, leftIndex, currentLeftIndex - 1);
        quickSort(array, currentRightIndex + 1, rightIndex);
    }

    /**
     * 归并排序
     * 分治:反复切割成两个部分,直至成单个元素
     * 合并有序数组:反复将两个有序数组,合成一个有序数组
     * 等值元素不会交换位置;需新增数组存储有序元素
     * @param array
     */
    private static void mergeSort(int[] array) {
        int length = array.length;
        int[] temp = new int[length]; // 每次归并有序数组时寄存排序的值
        mergeSort(array, 0, length - 1, temp);
    }

    /**
     * 分治
     * @param array
     * @param leftIndex
     * @param rigthIndex
     * @param temp
     */
    private static void mergeSort(int[] array, int leftIndex, int rigthIndex, int[] temp) {
        if(leftIndex >= rigthIndex){ // 只有一个元素时,无需分裂
            return;
        }

        int midIndex = (rigthIndex + leftIndex) / 2;
        mergeSort(array, leftIndex, midIndex, temp); // 会使array的leftIndex到midIndex有序
        mergeSort(array, midIndex + 1, rigthIndex, temp); // 会使array的midIndex + 1到rigthIndex有序
        merege(array, leftIndex, midIndex, rigthIndex, temp);
    }

    /**
     * 合并两个有序数组
     * @param array
     * @param leftIndex
     * @param midIndex
     * @param rigthIndex
     * @param temp
     */
    private static void merege(int[] array, int leftIndex, int midIndex, int rigthIndex, int[] temp) {
        int sortedPart1LeftIndex = leftIndex;
        int sortedPart1ReightIndex = midIndex;
        int sortedPart2LeftIndex = midIndex + 1;
        int sortedPart2RightIndex = rigthIndex;
        int tempIndex = 0;
        while(sortedPart1LeftIndex <= sortedPart1ReightIndex && sortedPart2LeftIndex <= sortedPart2RightIndex){
            if(array[sortedPart1LeftIndex] <= array[sortedPart2LeftIndex]){
                temp[tempIndex++] = array[sortedPart1LeftIndex++];
            } else {
                temp[tempIndex++] = array[sortedPart2LeftIndex++];
            }
        }

        while(sortedPart1LeftIndex <= sortedPart1ReightIndex){
            temp[tempIndex++] = array[sortedPart1LeftIndex++];
        }

        while(sortedPart2LeftIndex <= sortedPart2RightIndex){
            temp[tempIndex++] = array[sortedPart2LeftIndex++];
        }

        tempIndex = 0;
        while(leftIndex <= rigthIndex){
            array[leftIndex++] = temp[tempIndex++];
        }
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风铃峰顶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值