算法学习——递归与分治策略

分治法的基本思想

将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。

 

一般设计模式

f(p){

递归出口

分解

for(i = 1;i <= k;i++){

  yi = f(pi);   // for循环的此部分为递归求解过程

}

return merge(y1,...,yk);

 

例子

1、归并排序

思想:用分治策略实现对n个元素排序

时间复杂度:最好O(nlogn),平均O(nlogn)

实现:

public class MergeSort {

    /**
     * 入口函数
     * @param a
     */
    public void MergeSort(int[] a){

        int[] temp = new int[a.length];
        mergeSort(a,0,a.length-1,temp);
        System.out.println(Arrays.toString(a));
    }


    /**
     * 主处理函数
     * @param a 输入的数组
     * @param start 开始index
     * @param end 结束index
     * @param temp 临时数组temp
     */
    public void mergeSort(int[] a,int start,int end,int[] temp){

        // 直到start >= end 递归结束
        if(start < end){
            int mid = (end+start)/2;
            // 递归排序左半部分
            mergeSort(a,start,mid,temp);
            //递归排序由半部分
            mergeSort(a,mid+1,end,temp);
            //拍好后把temp的结果更改放到原数组中
            mergeArr(a,start,mid,end,temp);
        }
    }

    /**
     * 把temp数组中的结果放到a中
     * @param a
     * @param start
     * @param mid
     * @param end
     * @param temp
     */
    public void mergeArr(int[] a,int start,int mid,int end,int[] temp){
        int i = start;
        int j = mid+1;
        int k = 0;
        // 所有小的元素放到前面,大的元素放到后面
        while(i <= mid && j <= end){
            if(a[i] <= a[j]){
                temp[k++] = a[i++];
            }else{
                temp[k++] = a[j++];
            }
        }

        while(i <= mid){
            temp[k++] = a[i++];
        }

        while(j <= end){
            temp[k++] = a[j++];
        }

        for(i = 0;i < k;i++){
            a[i+start] = temp[i];
        }

    }


}

 

2、快速排序

思想:分治策略

基本动作:“交换”

基本过程(分治三步骤):

1)分解:以a[q]为基准元,将a[p….r]经过一系列的变换分成三段,a[p,q-1],a[q],a[q+1,r]

2)递归:对a[p,q-1]和a[q+1,r]进行递归排序

3)合并:不需要此步骤,过程中已经排好

时间复杂度:最好O和平均为(nlogn),最坏为O(n²),其运行时间与划分是否对称有关,与交换次数无关

实现(随机快排):

参考了blog:https://blog.csdn.net/MoreWindows/article/details/6684558

public class QuickSort {
    
    /**
     * 划分主体
     * @param a
     * @param l
     * @param r
     * @return
     */
    public int partition(int[] a,int l,int r) {
        // 生成一个随机下标,随机选择基准元,可期望划分是比较对称的。
        int k = getRandomIndex(l,r);
        // 这里一定要swap,否则每一次递归生成的k都不一样,会导致结果错误
        swap(a,l,k);
        int i = l, j = r, x = a[l];

        while (i < j) {
            while (i < j && a[j] >= x) {
                j--;
            }

            if (i < j) {
                a[i] = a[j];
            }

            while (i < j && a[i] < x) {
                i++;
            }

            if (i < j) {
                a[j] = a[i];
            }
        }
        a[i] = x;
        return i;
    }


    /**
     * 快排主体
     * @param a
     * @param l
     * @param r
     */
    public void quickSort(int[] a,int l,int r){

            if(l < r){
                int i = partition(a,l,r);
                quickSort(a,l,i-1);
                quickSort(a,i+1,r);
            }

        }



    public int getRandomIndex(int l,int r){
        return new Random().nextInt(r-l+1) + l;
}

    public void swap(int[] a,int i,int j){
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

 

 

    原文作者:递归与分治算法
    原文地址: https://blog.csdn.net/lianup/article/details/84991595
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞