「数据结构与算法」基础排序

  • 快速排序
  • 冒泡排序
  • 选择排序
  • 归并排序

快速排序

思路

1. 选定pivot中心数
2. 将所有大于pivot的数字放在pivot的右边
3. 将所有小于pivot的数字放在pivot的左边
4. 分别对左右子序列重复前三步

实现

    public static void quickSort(int[] array, int l, int r) {
        int leftPos = l;
        int rightPos = r;

        // 支点
        // 该值可以选任意值
        int pivot = array[(l + r) / 2];

        // 支点左边的值全部小于支点
        // 支点右边的值全部大于支点
        while (leftPos <= rightPos) {
            // 从左开始,寻找比支点大的位置
            while (array[leftPos] < pivot) {
                leftPos++;
            }

            // 从右开始,寻找比支点小的位置
            while (array[rightPos] > pivot) {
                rightPos--;
            }

            if (leftPos <= rightPos) {
                // 交换左右数值
                int temp = array[leftPos];
                array[leftPos] = array[rightPos];
                array[rightPos] = temp;
                leftPos++;
                rightPos--;
            }
        }

        if (rightPos > l) {
            quickSort(array, l, rightPos);
        }

        if (leftPos < r) {
            quickSort(array, leftPos, r);
        }
    }

冒泡排序

思路

俩俩交换,大的放在后面,第一次排序后最大值已在数组末尾
因为俩俩交换,需要 n-1 趟排序,比如10个数,需要9趟排序

实现

    public static void popupSort(int[] array) {
        // 每一轮把最大的值像冒泡泡一样冒到最后一位
        for (int i = 0; i < array.length - 1; i++) {
            // 判断是否修改
            boolean isChange = false;
            for (int j = 0; j < array.length - 1 - i; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;

                    isChange = true;
                }
            }

            // 若无修改代表数组已经有序
            if (isChange == false) {
                break;
            }
        }
    }

选择排序

思路

找到数组中最大的元素,与数组最后一位元素交换
当只有一个数时,则不需要选择了,因此需要n-1趟排序,比如10个数,需要9趟排序

实现

    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            int maxPos = 0;
            for (int j = 0; j < array.length - i; j++) {
                if (array[j] > array[maxPos]) {
                    // 获取最大值的位置
                    maxPos = j;
                }
            }
            // 交换
            int temp = array[maxPos];
            array[maxPos] = array[array.length - 1 - i];
            array[array.length - 1 - i] = temp;
        }
    }

插入排序

思路

将一个元素插入到已有序的数组中,在初始时未知是否存在有序的数据,因此将元素第一个元素看成是有序的
与有序的数组进行比较,比它大则直接放入,比它小则移动数组元素的位置,找到个合适的位置插入
当只有一个数时,则不需要插入了,因此需要n-1趟排序,比如10个数,需要9趟排序

实现

    public static void insertSort(int[] array) {
        // 默认第0位有序
        for (int i = 1; i < array.length; i++) {
            int temp = array[i];
            int pos = i;
            while (pos >= 1 && array[pos - 1] > temp) {
                // 寻找合适位置
                array[pos] = array[pos - 1];
                pos--;
            }
            // 找到合适位置
            array[pos] = temp;
        }
    }

归并排序

思路

将两个已排好序的数组合并成一个有序的数组(分治、拆、合)

  • 将元素分隔开来,看成是有序的数组,进行比较合并
  • 不断拆分和合并,直到只有一个元素

实现

    public static void mergeSort(int[] array, int l, int r) {
        if (l == r) {
            return;
        }
        int m = (r - l) / 2 + l;
        mergeSort(array, l, m);
        mergeSort(array, m + 1, r);
        // 合并
        merge(array, l, m + 1, r);
    }

    /**
     * 合并数组
     * @param array 数组
     * @param l 左部位置
     * @param m 中部位置
     * @param r 右部位置
     */
    private static void merge(int[] array, int l, int m, int r) {
        // 左数组
        int[] leftArray = new int[m - l];
        // 右数组
        int[] rightArray = new int[r - m + 1];
        // 填充数据
        for (int i = l; i < m; i++) {
            leftArray[i - l] = array[i];
        }
        // 填充数据
        for (int i = m; i <= r; i++) {
            rightArray[i - m] = array[i];
        }
        int i = 0;
        int j = 0;
        int startPos = l;
        // 依次比较两个数组中的值
        while (i < leftArray.length && j < rightArray.length) {
            if (leftArray[i] < rightArray[j]) {
                array[startPos] = leftArray[i];
                startPos++;
                i++;
            } else {
                array[startPos] = rightArray[j];
                startPos++;
                j++;
            }
        }
        // 右部用光了,把左部填充进去
        while (i < leftArray.length) {
            array[startPos] = leftArray[i];
            startPos++;
            i++;
        }
        // 左部用光了,把右部填充进去
        while ((j < rightArray.length)) {
            array[startPos] = rightArray[j];
            startPos++;
            j++;
        }
    }

山庄的铁匠
15 声望11 粉丝