数据结构及算法 | 递归和排序之递归函数、快速排序和归并排序

本文深入解析递归函数原理及其实现,包括二分查找、快速排序、归并排序等经典算法。通过代码示例,详细阐述了每种算法的工作流程与优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、递归函数

1、原理:
递归的实质就是函数调用自身,过程分为递过去和归回来两个部分。
递过去:缩小范围
归回来:计算值
递归函数需要注意的两个点:
1、判断递归结束的条件
2、判断n与n-1之间的关系
更具体的解释看图理解,语言能力有限!用递归求6!的结果:在这里插入图片描述
2、代码如下:

private boolean func3(int[] arr) {
    return func3(arr, 0, arr.length-1);
}
private boolean func3(int[] arr, int i, int j) {
    if(i+1 > j){
        return true;
    }
    if(arr[i] > arr[i+1]){
        return false;
    }
    return func3(arr, i+1, j);
}

递归实现二分查找:

public void test03(){
    int[] arr = new int[]{2,5,7,54,89,320,1300};
    int idx = binarySearch(arr, 0, arr.length-1, 54);
    System.out.println("54 idx:" + idx);
}
/**
 * 递归实现二分查找
 * binarySearch在arr数组中从i到j的范围内,用二分查找搜索val
 */
private int binarySearch(int[] arr, int i, int j, int val) {
    if(i > j){
        return -1;
    }
    int mid = (i+j)/2;
    if(val < arr[mid]){ // i mid-1
        return binarySearch(arr, i, mid-1, val);
    } else if(val > arr[mid]){
        return binarySearch(arr, mid+1, j, val);
    } else {
        return mid;
    }
}

二、快速排序算法

1、原理:
将给定数组中的元素按照从小到大的顺序排列,用快速排序算法解决过程是,将第一个元素作为基准元素,然后分别从数组的两端扫描数组,设两个指示标志(first指向起始位置,last指向末尾),首先从后半部分开始,如果发现有元素比该基准点的值小,就交换first和last位置的值,然后从前半部分开始扫秒,发现有元素大于基准点的值,就交换first和last位置的值,如此往复循环,直到first>=last,然后把基准点的值放到first这个位置。一次排序就完成了。以后采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组就自然有序了。
2、代码实现如下:

public void test04(){
    int[] arr = new int[20];
    for (int i = 0; i < arr.length; i++) {
        arr[i] = (int)(Math.random()*100);
    }
    quickSort(arr, 0, arr.length-1);
    System.out.println(Arrays.toString(arr));
}

private void quickSort(int[] arr, int i, int j) {
    if(i > j) {
        return;
    }
    int l = partation(arr, i, j); // left == right
    quickSort(arr, i, l-1);
    quickSort(arr, l+1, j);
}

private int partation(int[] arr, int l, int r) {
    int val = arr[l];
    while(l < r){
        // 1. 从r开始往l的方向找第一个小于val的数字
        while(l < r && arr[r] > val){
            r--;
        }
        // 2. 把第一个小于val的元素值写入l里面,并且l++
        if(l < r){
            arr[l++] = arr[r];
        }
        // 3. 从l往r的方向找第一个大于val的数字
        while(l < r && arr[l] < val){
            l++;
        }
        // 4. 把第一个大于val的元素值写入r里面,并且r--
        if(l < r){
            arr[r--] = arr[l];
        }
    }
    arr[l] = val;
    return l;
}

3、快速排序算法的优化
1、当快速排序到范围小到一定成度的时候,用插入排序
2、三数取中法
3、随机数法
注:2和3的目的是选一个合适的基准数,尽量减少快排分割的次数

三、归并排序

1、原理:
归并排序是一种外部排序,用于内存有限制,数据无法一次性放入内存的问题。
将给定数组中的元素进行从小到大的排序,用归并排序的思想就是,将一组数据取第一个元素坐标与最后一个元素坐标和的二分之一,作为基准数的下标(只看下标,不看下表对应的元素值)将原有数组分为两部分,再对这两部分用同样的分割方法直到都分割到只剩下一个元素为止;然后再将这些分割的元素从下往上依次进行有序的合并,具体看图可能更好理解。在这里插入图片描述
2、代码如下:

public class MergeSort {
    public static void main(String[] args) {
        int[] arr = new int[20];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int)(Math.random()*100);
        }
        mergeSort(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    /**
     * 实现归并排序
     */
    private static void mergeSort(int[] arr, int i, int j) {
        if(i < j) {
            int mid = (i+j)/2;
            /**
             * 以下的操作,先进行数组划分,直到划分为单个元素以后,逐级向上回溯
             * 的时候,进行合并操作
             */
            mergeSort(arr, i, mid);
            mergeSort(arr, mid+1, j);
            merge(arr, i, j); // 合并两个有序的序列
        }
    }
    /**
     * 合并两个有序的序列
     */
    private static void merge(int[] arr, int low, int high) {
        int[] tmp = new int[high-low+1];
        int mid = (low+high)/2;  // i-mid mid+1-j
        int i=low; // [i, mid]
        int j=mid+1; // [mid+1, high]
        int idx=0;
        
        while(i <= mid && j <= high){
            if(arr[i] > arr[j]){
                tmp[idx++] = arr[j++];
            } else {
                tmp[idx++] = arr[i++];
            }
        }
        while(i <= mid){  //
            tmp[idx++] = arr[i++];
        }
        while(j <= high){
            tmp[idx++] = arr[j++];
        }
        // 把tmp里面合并的有序段再写回arr的[low,high]
        for(int k=low; k<=high; ++k){
            arr[k] = tmp[k-low];
        }
    }
}

3、应用场景:
用于解决外部排序的问题(文件的操作):例如
现在有50亿个整数,内存限制200M,问你该怎么对这50亿个整数进行排序?
50亿 = 5G * 4 = 20G
步骤一:
先生成100个小文件,每个文件保存一部分数据
步骤二:
将这10个小文件用顺序合并

注: 大文件里面的整数 % 100 = 小文件的下标
一亿个整数的文件, 内存限制4M
附:如下是常用的数字记忆

  • 100M * 4 = 400M
  • 1G = 10亿
  • 100M = 1亿
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值