算法回顾 : 归并排序、快速排序、堆排序

目录

归并排序

快速排序

堆排序


归并排序

将数组 arr[ n ]  分为左、右两部分,左与右再各自分两部分。不断重复二分,直到左与右都仅剩一个数。

对 左半数组 和 右半数组 进行 合并排序。

 从分割到长度 1的数组开始,不断往回 合并 左,右数组 并排序。直到恢复原长。

public static void main(String[] args) {
    int[] arr = {3,7,1,9,2,88,6,5};

    sort(arr,0, (arr.length - 1));

    for (int i = 0; i < arr.length; i++) {
        System.out.print(arr[i] + " ");
    }
}
// L:左边界,R:右边界
private static void sort(int[] arr, int L, int R) {
    if (L == R) {
        return;
    }

    int mid = L + ((R - L) / 2); // 取中点
    sort(arr, L, mid);
    sort(arr, mid + 1, R);
    merge(arr, L, mid, R);
}
​//合并 左半数组 和 右半数组
private static void merge(int[] arr, int L, int mid, int R) {

    int[] help = new int[R - L + 1]; // 合并后的数组

    int i = 0;        // help[]初始位置
    int p1 = L;       // 左半数组 L->mid     初始位置 p1
    int p2 = mid + 1; // 右半数组 (mid+1)->R 初始位置 p2

    //左与右数组 从初始位置进行比较 : p1 与 p2 位置相比较,谁小,谁插入 help[],并后移
    while (p1 <= mid && p2 <= R) {

        help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }

    // 上方for循环 必然越界跳出。 即 : 左 与 右 必然有一个先全部插入后 ++ 越界
    // 即,出现 左数组:  1,8,9 .  右数组 2,3,4时
    // help[] 已插入 1,2,3,4 . 剩余 8,9 未能插入。就因为 p2 >R 而 循环结束


    // 越界情况处理 , 两个 while 仅一个生效

    // 右数组完全插入后 越界时 ,左数组始终小于 mid
    while (p1 <= mid) {
        help[i++] = arr[p1++];
    }

    // 左数组越界时
    while (p2 <= R) {
        help[i++] = arr[p2++];
    }

    // 将 help[] 拷贝到 arr[] 中
    for (int x = 0; x < help.length; x++) {
        arr[L + x] = help[x];
    }
}
public static void swap(int[] arr, int x,int y) {
    temp = arr[x];
    arr[x] = arr[y];
    arr[y] = temp;
}

 

快速排序

默认将数组末尾当作中间值。如图,中间值为 3

设置大于区域,和小于区域。  我们准备把 大于中间值的,放入大于区域;小于中间值的,放入小于区域。

指针从头开始探测。

当探测到的数,大于中间值 :交换 指针位置和大于区域外侧大于区域扩大指针不动

当探测到的数,等于中间值 :指针右移

当探测到的数,小于中间值 :交换 指针位置和小于区域外侧小于区域扩大指针右移

当,指针触碰大于区时,结束。同时,记录 等于区域 范围

分别在小于区、大于区。递归地重复此操作。

public static void main(String[] args) {
    int[] arr = {2,3,8,1,3,2,7,4,5,3};

    quickSort(arr, 0, arr.length-1);

    for (int i = 0; i < arr.length; i++) {
        System.out.print(arr[i]+" ");
    }
}
public static void quickSort(int[] arr, int L, int R) {

    if (L < R) {
        int[] p = partition(arr, L, R);

        //去除 等于区域,进行递归
        quickSort(arr, L, p[0] - 1);
        quickSort(arr, p[1] + 1, R);
    }

}
private static int[] partition(int arr[], int L, int R) {

    int less = L - 1;// 小于区域,从左边界外 -1开始

    int more = R + 1;    // 大于区域,从 右边界外 R +1  开始

    // 默认 数组 最后一个数 arr[R] 作为中间值
    int midValue = arr[R];

    // 视 L 为探测指针,当碰触大于区域,结束循环
    // 仅当 探测值 小于等于 中间值,指针移动。
    while (L < more ) {

        if (arr[L] < midValue) {               //当探测到小于 中间值
            SortUtil.swap(arr, ++less, L++); //将 小于区域的下一个位置,与探测到的值 交换
                                             // 小于区域 右移,探测指针右移

        }else if (arr[L] > midValue) {  // 探测到大于中间值时

            SortUtil.swap(arr, L, --more);   // 交换 大于区域左侧位置与探测位置,探测指针仍然停留
            //注意 !!!!! 探测指针不移动 !!!!!  仅大于区域左移

        } else {
            L++; // 与中间值相等,指针右移
        }

    }

    return new int[]{less + 1, more-1}; // 返回 等于中间值的区域
}

堆排序

1.构建大根堆

2.将 堆顶堆最后一个元素交换。 减小堆 (剪除最后一个元素)

3.从堆顶开始重构大根堆。(与左右孩子最大值比较,如果比最大值小,则交往两者位置,继续往下判断)

重复 2,3步骤,直到堆大小减为0

被剪除部分已排序完成

public static void main(String[] args) {
    int[] arr = {2,3,8,1,3,2,7,4,5,3};
    heapSort(arr);

    for (int i = 0; i < arr.length; i++) {
        System.out.print(arr[i]+" ");
    }
}
public static void heapSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }

    //构建大根堆
    for (int i = 0; i < arr.length; i++) {
        heapInsert(arr, i);
    }

    int heapSize = arr.length;

    SortUtil.swap(arr, 0, (heapSize-1)); //交换堆顶与最后一个元素位置
    heapSize--;//减小堆

    while (heapSize > 0) {
        heapify(arr, 0, heapSize); // 重构大根堆
        SortUtil.swap(arr, 0, (heapSize - 1)); //交换堆顶与最后一个元素位置
        heapSize--; //减小堆
    }
}
/**
 * 构建大根堆
 * @param arr
 * @param index 待判断节点
 */
private static void heapInsert(int[] arr, int index) {

    //若 该节点 大于 其父节点 : 则交换两者位置 ,继续向上 比较父节点
    while (arr[index] > arr[(index - 1) / 2]) {
        SortUtil.swap(arr, index, (index - 1)/2);
        index = (index - 1) / 2;
    }
}
/**
 * 重构大根堆
 * @param arr
 * @param heapSize 堆大小 (不断减小)
 * @param index    堆顶
 */
private static void heapify(int[] arr, int index,int heapSize) {

    int left = index * 2 + 1; //左孩子

    while (left < heapSize) {

        // 右孩子、左孩子 取最大孩子
        int big = (left + 1) < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;

        // 如果 小于 最大孩子
        if (arr[index] < arr[big]) {
            SortUtil.swap(arr, index, big);//交换两者位置
        }else {
            break;
        }

        // 继续往下判断
        index = big;
        left = index * 2 + 1;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值