分治法和递归

   说起递归,可能都比较熟悉。经典的汉诺塔和斐波那契数问题,相信在熟悉不过,那就从递归开始吧!
   **递归**:简单来说就是,函数自己直接或者间接调用自己;递归算法对解决一大类问题很有效,它可以使算法简洁和易于理解。递归往往能给我们带来非常简洁非常直观的代码形势,从而使我们的编码大大简化,然而递归的思维确实很我们的常规思维相逆的,我们通常都是从上而下的思维问题, 而递归趋势从下往上的进行思维。这样我们就能看到我们会用很少的语句解决了非常大的问题,所以递归策略的最主要体现就是小的代码量解决了非常复杂的问题。
   **使用递归满足的3个条件**:
   (1)函数自己调用自己;
   (2)有趋于终止的条件;
   (3)有递归方程;
   **分治法的基本思想**:将一个规模为n的问题,把它划分为k个子问题,且满足这些子问题之间相互独立、性质相同,递归求解这些子问题,将这些子问题的解合并之后可以得到原问题的解。
   **分治法解决的问题具有的特征**:
   (1)该问题缩小到一定程度就很容易求解;
   (2)该问题具有最优子结构性质;
   (3)利用该问题分解的子问题的解合并后可以得到原问题的解;
   (4)该问题分解的子问题都是相互独立的;
   说完理论,就来看些例子吧~
  • 二分搜索技术
    基本思想:将n个元素分成个数大致相同的凉拌,取a[n/2]与x进行比较;如果x=a[n/2],算法停止。如果x<a[n/2],则在数组a的左侧进行寻找;反之,在a的右侧寻找。
public class TestDemo {
    public static int binarySearch(int[] a,int key){
        int left = 0;
        int right = a.length-1;
        while(left <= right){
            int middle = (left+right)/2;
            if (key == a[middle]) {
                return middle;
            }
            if (key > a[middle]){
                left = middle+1;
            }
            else {
                right = middle-1;
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] a = {1,3,4,5,7,8};
        Scanner sc = new Scanner(System.in);
        int key = sc.nextInt();
        int ret = binarySearch(a,key);
        System.out.println("你要找的数字的下标是" + ret);
    }

}

算法的时间复杂度为O(logn);

  • 合并排序
    基本思想:将待排序元素分成大小大致相同的2个子集,分别对两个子集进行排序,最终将排好序的自己合并为所要求的排好序的集合;
public class Demo {
    public static void merge(Comparable[] c,Comparable[] d,int l,int m,int r){
        //合并c[1:m]和c[m+1:r]到d[1:r]
        int i = 1;
        int j = m+1;
        int k = 1;
        while((i <= m) && (j <= r)){
            if (c[i].compareTo(c[j]) <= 0){
                d[k++] = c[i++];
            }else {
                d[k++] = c[j++];
            }
            if (i>m){
                for (int q = j; q <= r ; q++) {
                    d[k++] = c[q];
                }
            }else {
                for (int q = i; q <= m ; q++) {
                    d[k++] = c[q];
                }
            }
        }
    }
    public static  void mergePass (Comparable[] x,Comparable[] y,int s){
        //合并为大小为s的相邻子数组
        int i = 0;
        while(i<x.length-2*s){
            merge(x,y,i,i+s-1,i+2*s-1);
            i = i+2*s;
        }
        if (i+s < x.length){
            merge(x,y,i,i+s-1,x.length-1);
        }else {
            for (int j = i; j < x.length; j++) {
                y[j] = x[j];
            }
        }
    }
   
}

时间复杂度
当n≤1时,T(n) = O(1);
当n>1时,T(n) = O(nlogn);

  • 快速排序
    基本思想:对输入的子数组a[p:r]进行以下操作
    (1)分解:
    将a[p:r]以a[p]为基准,把它分成a[p:q-1],a[q]和a[q+1,r],使得a[p:q-1]中的元素均小于等于a[q],a[q+1:r]中的元素均大于a[q]
    (2)递归求解:调用快速排序,对a[p:q-1]和a[q+1:r]进行排序
    (3)合并


import java.util.Arrays;
import java.util.Scanner;

public class QuickSort {
	
	public static void quickSort(int[] arr, int low, int high) {
		if (low >= high) {
			return;
		}
		int left = low;
		int right = high;
		int temp = arr[low]; // 基准元素
		while (low < high) {
			while (low < high && arr[high] >= temp) {
				high--;
			}
			if (low < high) {
				arr[low] = arr[high];
				low++;
			}
			while (low < high && arr[low] < temp) {
				low++;
			}
			if (low < high) {
				arr[high] = arr[low];
				high--;
			}
		}
		arr[low] = temp;
		
		quickSort(arr, left, low - 1);
		quickSort(arr, low + 1, right);
	}
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt(); // 数组的长度
		int[] arr = new int[n];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = scanner.nextInt();
		}
		scanner.close();
		quickSort(arr, 0, arr.length - 1);
		System.out.println(Arrays.toString(arr));
	}

}


算法的时间复杂性分析:
最好情况:T(n) = O(nlogn);
平均情况:T(n) = O(nlogn);
最坏情况:T(n) = O(n^2);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值