常见排序算法(二)

归并排序

归并排序是一种分治法思想实现的排序,假如有一个数组9,3,7,2,8,5,1,4
先分割到最小,然后每一块各自排序。看图
图片.png
分到只有一个数的时候(一个数肯定有序)开始合并,这就是“合并两个有序数组”
那先学一下合并两个有序数组这个算法
LeetCode.88
图片.png
为什么要叫“非递减顺序”,直接叫“递增”不好吗。。

改成,一个数组中的x个有序区间

图片.png
用递归,把这个数组分为两个有序区间,然后每次比较起点位置的数,小的放进结果数组

/**
 * Description 将一个数组分为两个有序数组,依次互相比较,小的放进结果数组
 * date 2023/10/17 17:21
 * @param arr 待排序的原数组
 * @param i 第一个区间的左边界
 * @param iEnd 第一个区间的右边界
 * @param j 第二个区间的左边界
 * @param jEnd 第二个区间的有边界
 * @param rs 结果数组
 * @param k 结果数组的参数
 * @author zqh
 * @since JDK 1.8
 */
public static void merge(int[] arr,int i,int iEnd,int j,int jEnd,int [] rs,int k){

}

第一次分割后,i=1,j=2,比较这两个起点,谁更小谁放进结果数组,第一次递归调用后,rs有一个1。
第二次递归调用,i=5,j=2,把2放进结果数组,rs=1,2…
假如有一个区间没有元素了(当i>iEnd或者j>jEnd),另一个区间还剩下大于1个元素,像这样图片.png,就不用比较了,直接把剩下的元素复制到结果数组中。这也是递归的结束条件
最终
图片.png

import com.sun.istack.internal.NotNull;

import java.util.Arrays;

/**
 * Description 归并排序学习,B站黑马数据结构课
 * date 2023/10/17 18:29
 *
 * @author zqh
 * @since JDK 1.8
 */
public class MergeSort {

    public static void main(String[] args) {
        int[] arr = new int[]{12, 5, 8, 7, 3, 2, 9, 4, 10, 6, 1};
        mergeSort(arr);
        for (int i : arr) {
            System.out.print(" " + i);
        }
    }

    /**
     * Description 归并排序
     * date 2023/10/17 18:28
     *
     * @param arr 待排序数组
     * @author zqh
     * @since JDK 1.8
     */
    public static void mergeSort(int[] arr){
        // 创建临时数组
        int[] rs = new int[arr.length];
        // 初始范围
        split(arr,0,arr.length-1,rs);
    }
    /**
     * Description 递归分割数组
     * date 2023/10/17 16:46
     * @param arr 待排序数组
     * @param left 数组左边界
     * @param right 数组有边界
     * @author zqh
     * @since JDK 1.8
     */
    private static void split(int[] arr,int left,int right,int[] rs){
        // left=right,证明范围内只有一个数据了,停止递归
        if (left == right){
            return;
        }
        // 找中间点,分割一半
        int mid = (left+right)/2;
        // 递归,分割后左边的范围为left到中间点
        split(arr,left,mid,rs);
        // 右边的范围为mid+1到right
        split(arr,mid+1,right,rs);
        // 合并两个有序数组,注意临时数组的启始位置为left
        merge(arr,left,mid,mid+1,right,rs,left);
        // 把rs数组的元素复制到原arr数组
        System.arraycopy(rs,left,arr,left,right-left+1);
    }

    /**
     * Description 将一个数组分为两个有序数组并分别排序再合并
     * date 2023/10/17 17:21
     * @param arr 待排序的原数组
     * @param i 第一个区间的左边界
     * @param iEnd 第一个区间的右边界
     * @param j 第二个区间的左边界
     * @param jEnd 第二个区间的有边界
     * @param rs 结果数组
     * @param k 结果数组复制时用的下标,启始为0
     * @author zqh
     * @since JDK 1.8
     */
    public static void merge(int[] arr,int i,int iEnd,int j,int jEnd,
                             int [] rs,int k){
        // 递归终止条件
        if (i>iEnd){
            // 复制另一个区间的元素到结果元素
            System.arraycopy(arr,j,rs,k,jEnd-j+1);
            return;
        }
        if (j>jEnd){
            System.arraycopy(arr,i,rs,k,iEnd-i+1);
            return;
        }
        // 左边小于右边的情况,i<j
        if (arr[i] < arr[j]){
            rs[k] = arr[i];
            merge(arr,i+1,iEnd,j,jEnd,rs,k+1);
        }else {
            // j小的情况
            rs[k] = arr[j];
            merge(arr,i,iEnd,j+1,jEnd,rs,k+1);
        }
    }
}

快速排序

在一个数组里选择有边界为基准元素,然后比它小的放在它左边,比它大的放在它右边,然后再在子数组里重复这个过程。

具体过程,找的基准元素后,找一个比他大的数,设置为第二指针。
然后把基准元素和第二指针后面的元素比较,如果后面的元素小于基准元素,就交换第二指针和这个较小元素的位置。然后第二指针+1,循环。最后找完后,交换基准元素和第二指针的位置,把基准元素方中间。

import java.util.Arrays;

/**
 * Description 快速排序
 * date 2023/10/18 15:02
 *
 * @author zqh
 * @since JDK 1.8
 */
public class QuickSort {
    public static void main(String[] args) {
        int[] arr = new int[]{2,5,9,6,1,3,8};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    /**
     * Description
     * date 2023/10/18 11:03
     * @param arr 待排序数组
     * @author zqh
     * @since JDK 1.8
     */
    public static void quickSort(int[] arr,int left,int right){
        if (left<right){
            // 分区
            int position = partition(arr, left, right);
            // 递归调用,左子数组
            quickSort(arr,left,position-1);
            // 递归调用,右子数组
            quickSort(arr,position+1,right);
        }

    }
    /**
     * Description 	分区排序,排完一次就代表一个基准点有序
     * date 2023/10/18 10:48
     * @param arr 待排数组
     * @param left 左边界
     * @param right 有边界
     * @return 基准元素排好后的位置
     * @author zqh
     * @since JDK 1.8
     */
    private static int partition(int[] arr,int left,int right){
        // 定义基准元素为右边界
        int p = arr[right];
        // 定义比基准元素大的第二指针,初始化为左边界
        int pointer = left;
        // 遍历数组中所有元素,进行比较
        for (int i = left; i < right; i++) {
            // 如果有元素小于基准元素
            if (arr[i] < p){
                // 交换这个元素和第二指针的位置
                int temp = arr[i];
                arr[i] = arr[pointer];
                arr[pointer] = temp;
                // 第二指针+1
                pointer++;
            }
        }
        // 排序结束后,要把基准元素和第二指针交换。让基准元素到中间
        int temp = arr[pointer];
        arr[pointer] = arr[right];
        arr[right] = temp;
        // 返回第二指针的位置
        return pointer;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值