算法与设计(王晓东第四版)第二章(递归与分治策略)上

递归:

阶乘:

import java.util.Scanner;
public class factorial {
    public static int factorialdemo(int n)
    {
        if(n==0)return 1;
        else return n*factorialdemo(n-1);
    }
    public static void main(String [] args)
    {
        Scanner sc = new Scanner(System.in);
        int a=sc.nextInt();
        int b=factorialdemo(a);
        System.out.println(b);
        sc.close();
    }
}

输出结果:

(1)

 (2)

(3) 

 

结论:

显然输入的原数据越大,操作时间越长

分治:

概念:将一个规模较大的问题,分成k个子问题,分别求出每个子问题的解,合并起来就变成了原问题的解。每个子问题的规模要大致相当,这样效率最高

当规模为n时的时间效率:

二分检索法:

public static int BinarySearch(int[]a,int x,int n) {
        int left=0;
        int right=n-1;
        while(left<=right)
        {
            int middle=(left+right)/2;
            if(x==a[middle])return middle;
            if(x>a[middle])left=middle+1;
            else right=middle-1;
        }
        return -1;
    }
    public static void main(String [] args)
        {
            int i,j,k,f;
            Scanner sc=new Scanner(System.in);
            System.out.println("请输入母数组长度");
            i=sc.nextInt();
            int[]a=new int[i];
            System.out.println("请输入母数组");
            for(f=0;f<i;f++)
                a[f]=sc.nextInt();
            System.out.println("请输入要查找的元素");
            j=sc.nextInt();
            k=BinarySearch(a, j, i)+1;
            if(k>0)
                System.out.println("该元素在第"+k+"位上");
            else
                System.out.println("该元素不在数组中");
            sc.close();
        }

输出结果:

(1)处理内容较多时,查找时间差距较大

时间效率最好结果:

时间效率最坏结果:

 (2)处理内容较少时,查找时间差距不大

时间效率最好结果:

 时间效率最坏结果:

大整数的乘法:

设X,Y都是n位的二进制整数,计算XY,直接每位相乘需要进行O(n^{2})步运算,使用大整数乘积算法,可大大节省运算时间

原来XY=(A2^{n}+B)(C2^{n}+D)=AC2^{n}+(AD+CB)2^{n}+BD

时间效率为

现将XY改写为AC2^{n}+((A-B)(D-C)+AC+BD)2^{n/2}+BD,则现在只需要计算三次n/2位整数的乘法【AC,BD,(A-B)(D-C)】

此时时间效率为

大大减少了运算次数

 Strassen矩阵乘法:

定义矩阵C[I][j]= \sum_{k=1}^{n}A[I][k]B[I][j],计算的时间效率为O(n^{3}),设n为2的幂,A,B,C都可分成4个(n/2)*(n/2)的方阵,通过计算8个n/2阶方阵的乘积和4个n/2阶方阵的加法,时间效率为

该方法并没有提高效率,本质原因是没有减少乘法运算次数。Strassen提出了一种新算法,只用7次乘法,但增加了加减次数,运算方法如下


时间效率为

 计算时间复杂性有较大提升

棋盘覆盖:

在一个2^{k}*2^{k}(k>=0)方格组成的棋盘中,只有一个特殊方格和其他方格不同,特殊方格在棋盘上有4^{k}种情况,用L型骨牌覆盖除特殊方格外所有方格,且不能重叠,有(4^{k}-1)/3个骨牌,当k>0时,将棋盘分为四个2^{k-1}*2^{k-1}子棋盘,特殊方格必位于四个子棋盘之一中,用一个L型骨牌覆盖这三个字棋盘会和处,这样被L型骨牌覆盖的方格就成为该子棋盘中的特殊方格,就将原问题转化为四个规模较小的子问题,递归分割,直到棋盘简化为1*1的棋盘,问题就解决了


​​​​​​​

 代码实现:

public void chessBoard(int tr/*棋盘左上角方格行号*/,int tc/*棋盘左上角方格列号*/,int dr/*特殊方格行号*/,int dc/*特殊方格列号*/,int size/*棋盘规格 */)
    {
        int [][] board=new int [tr][tc];
        int tile=0;
        if(size==1)return;
        int t=tile++,//L型骨牌牌号
            s=size/2;//分割棋盘
        //覆盖左上棋盘
        if(dr<tr+s&&dc<tc+s)//特殊方格在此棋盘中
            chessBoard(tr,tc,dr,dc,s);
        else//此棋盘中无特殊方格
        {
            board[tr+s-1][tc+s-1]=t;//用t号L型骨牌覆盖右下角
            chessBoard(tr,tc,tr+s-1,tc+s-1,s);//覆盖其余方格
        }
        //覆盖右上棋盘
        if(dr>=tr+s&&dc<tc+s)
        chessBoard(tr,tc+s,dr,dc,s);
        else
        {
            board[tr+s-1][tc+s]=t;//用t号L型骨牌覆盖左下角
            chessBoard(tr,tc+s,tr+s-1,tc+s,s);
        }
        //覆盖左下棋盘
        if(dr>=tr+s&&dc>=tc+s)
        chessBoard(tr+s,tc,dr,dc,s);
        else
        {
            board[tr+s][tc+s-1]=t;//用t号L型骨牌覆盖右上角
            chessBoard(tr+s,tc,tr+s,tc+s-1,s);
        }
        //覆盖右下棋盘
        if(dr>=tr+s&&dc>=tc+s)
        chessBoard(tr+s,tc+s,dr,dc,s);
        else
        {
            board[tr+s][tc+s-1]=t;//用t号L型骨牌覆盖左上角
            chessBoard(tr+s,tc+s,tr+s,tc+s-1,s);
        }

主函数:

public static void main(String[]arg)
    {
        int rd,cd,size;
        System.out.println("请输入棋盘大小[应满足log2(size)为整数]");
        Scanner sc=new Scanner(System.in);
        size=sc.nextInt();
        int [][]chess=new int[size][size];
        System.out.println("请输入特殊方格位置");
        rd=sc.nextInt();
        cd=sc.nextInt();
        chess[rd][cd]=-1;
        chessBoard(0, 0, rd, cd, size,chess);
        System.out.println("棋盘:");
        for(int i=0;i<size;i++)
        {
            for(int j=0;j<size;j++)
                System.out.print(chess[i][j]+"\t");
            System.out.println();
        }
        sc.close();
    }

输出结果:

(1)数据量较小

(2)数据量较大

T(k)是该算法覆盖一个2^{k}*2^{k}棋盘所需时间

 T(k)=O(4^{k}​​​​​​​),该算法是一个在渐进意义下最优的算法

总结:

错误:

(1)System.out.println()输出一个结果占据一整行,如需多个数据输出在同一行,需用System.out.print()(与C++相似)

(2)java与C++区别之一是:java每个编写程序都必须规定其公用public(只有公用的数据可以在其他的程序中使用),或私有private属性(其他程序不能使用);

java中输入Scanner sc = new Scanner(System.in);int a=sc.nextInt();将输入的值赋给a

C++中输入cin>>a;

java中输出System.out.println("用时"+time+"纳秒");

C++中输入cout<<a;

(3)计时操作:

用long millis1=System.nanoTime()放在操作之前,该语句可获取当前的时间(精确到纳秒),将long millis2=System.nanoTime();放在操作之后,再次获取一个时间,最后两时间相减long time=millis2-millis1;就可以得到进行操作运算的具体时间

总结:

学习了java的基础编写,并在VScode上运用和熟悉相关操作,体会了各编写语言之间的差异。学习了java中递归的概念操作,和部分分治策略的编写思路

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值