15、快速排序和归并排序

1、简单的介绍

1、归并排序的核心思想:我们将把数组中的元素分成两部分,对左边元素进行排序,对右边元素进行排序。然后对左右两边元素,进行归并操作。
1、归并排序是稳定的。归并的过程,如果两个元素相等,先把左边的元素进行归并。
2、归并排序不是原地排序,需要额外的内存空间。O(n)
T(N)=2T(N/2)+O(N);
3、
master公式的使用
T(N) = a*T(N/b) + O(N^d)
1) log(b,a) > d -> 复杂度为O(N^log(b,a))
2) log(b,a) = d -> 复杂度为O(N^d * logN)
3) log(b,a) < d -> 复杂度为O(N^d)

归并排序的执行效率与要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,不管是最好情况、最坏情况,还是平均情况,时间复杂度都是 O(nlogn)。


2、快速排序核心思想:如果要排序数组中下标从 p 到 r 之间的一组数据,我们选择 p 到 r 之间的任意一个数据作为 pivot(分区点)。
我们遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放到右边,将 pivot 放到中间。
经过这一步骤之后,数组 p 到 r 之间的数据就被分成了三个部分,前面 p 到 q-1 之间都是小于 pivot 的,
中间是 pivot,后面的 q+1 到 r 之间是大于 pivot 的。

1、快速排序是原地排序,不需要额外的内存空间。
2、但是快速排序不是稳定的排序。
3、快速的排序最坏情况是原本有序,O(n^2)
4、最好的情况是分布均匀,O(nlogn)
5、平均时间复杂度是O(n*logn)

二、代码实现

 /**
     * 进行归并排序 基本思想是:我们把一个数组分成两个部分,左边排好序,然后右边的排好序,最后把两个进行归并。
     *
     * @param array
     */
    public static void MergeSort(int[] array) {
        if (array.length <= 1) {  //如果元素的个数小于等于1 不需要排序
            return;
        }
        MergeSort(array, 0, array.length - 1);

    }

    /**
     * l 表示的是要排序的下标最左边和最右边
     *
     * @param array
     * @param l
     * @param r
     */
    private static void MergeSort(int[] array, int l, int r) {
        if (l == r) {  //如果相等就表示排序到最后一个了。
            return;
        }
        int mid = l + ((r - l) >> 1);
        MergeSort(array, l, mid); //左边排好序
        MergeSort(array, mid + 1, r); //右边排好序
        merge(array, l, mid, r);  //然后进行归并
    }

    /**
     * 进行归并的操作
     *
     * @param array
     * @param l
     * @param mid
     * @param r
     */
    private static void merge(int[] array, int l, int mid, int r) {
        int arr[] = new int[r - l + 1];  //定义一个等长的数组
        int p = l;
        int q = mid + 1;
        int index = 0;
        while (p <= mid && q <= r) {  //就是进行两个数组之间的元素进行比较
            if (array[p] <= array[q]) {
                arr[index++] = array[p++];
            } else {
                arr[index++] = array[q++];
            }
        }
        while (p <= mid) {  //如果右边数组已经排序完
            arr[index++] = array[p++];
        }
        while (q <= r) {  //如果左边的数组排序完
            arr[index++] = array[q++];
        }
        for (int i = 0; i < arr.length; i++) {
            array[l + i] = arr[i];
        }
    }
 /**
     * 快速排序的基本思想:
     * 取数组中的第一个数或者最后一个数,或者说,是随机的一个数,作为值。
     * 把小于它的数,放在左边。大于它的数放在右边。
     * 后面的递归实现
     *
     * @param data
     */
    public static void quickSort(int[] data) {
        if (data.length <= 1) {  //如果元素的个数小于等于1 不需要排序
            return;
        }
        quickSort(data, 0, data.length - 1);
    }

    /**
     * @param data
     * @param l
     * @param r
     */
    private static void quickSort(int[] data, int l, int r) {
        if (l < r) {
            int index = (int) Math.random() * (r - l + 1);
            swap(data, l + index, r);  //和最后一个元素进行交换。
            int[] p = partition(data, l, r); //进行划分操作
            quickSort(data, l, p[0] - 1);
            quickSort(data, p[1] + 1, r);
        }
    }

    /**
     * 进行数据的划分,以最后一个元素为 基准  小于它的元素 放在左边
     * 大于它的放在右边
     *
     * @param data
     * @param l
     * @param r
     * @return
     */
    private static int[] partition(int[] data, int l, int r) {
        int less = l - 1; //less 表示的是包裹着比它小的元素
        int more = r;
        while (l < more) {
            if (data[l] > data[r]) {  //如果这个元素比较大,我们就进行交换
                swap(data, l, --more);  //最后一个元素,我们是不动的。
            } else if (data[l] < data[r]) {  //如果这个元素比较小,我们就放到前面来
                swap(data, ++less, l++);
            } else {  //相等的情况。
                l++;
            }
        }
        swap(data, more, r);
        return new int[]{less + 1, more};
    }

    /**
     * 进行数据的交换、
     *
     * @param data
     * @param i
     * @param j
     */
    private static void swap(int[] data, int i, int j) {
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值