约瑟夫环问题与递归问题(详解)

今天呢,阿Q给大家带来一个小故事,那就是著名的约瑟夫问题。公元66年,约瑟夫不情愿地参与领导了犹太同胞反抗罗马统治的起义,后来起义失败,他和一些宁死不降的起义者被困于一个山洞之中。罗马将军韦斯巴芗(Vespasian)派人来劝降,他主张投降,其余的人不答应,并以死相逼。最后,约瑟夫提议,与其死在自己的手上,不如死在彼此的手上。因此他便将游戏规则告知众人:N个人围成一圈,从第一个人开始报数,报到m的人被杀,剩下的人继续从1开始报数,报到m的人继续被杀;如此往复,直到剩下最后一个人。他就是运用这个游戏规则最终活了下来,被后人称为约瑟夫环问题。

接下来呢,就让我们用java代码来模拟一下故事的进程。

方式一:

public static void getLucklyNum(int num) {
    ArrayList<Integer> list = new ArrayList<>();        //创建集合存储1到num的对象
    for(int i = 1; i <= num; i++) {
        list.add(i);                                    //将1到num存储在集合中
    }

    int count = 1;                                      //用来数数的,只要是3的倍数就杀人
    for(int i = 0; list.size() != 1; i++) {             //只要集合中人数超过1,就要不断的杀
        if(i == list.size()) {                          //如果i增长到集合最大的索引+1时
            i = 0;                                      //重新归零
        }

        if(count % 3 == 0) {                            //如果是3的倍数                   
            System.out.println(list.get(i));
            list.remove(i--);                           //就杀人
        }
        count++;            
    }
}

方式二:

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();        //创建集合存储1到num的对象
    for(int i = 1; i <= 20; i++) {
        list.add(i);                                    //将1到num存储在集合中
    }
    cycleCal(list,1);
}


public static void cycleCal(ArrayList<Integer> list,int count) {
    int len = list.size();
    if (len > 1) {
        for (int i = 0; i < len; i++) {
            if (count == 3) {   //用来数数的,只要是3的倍数就杀人
                System.out.println(list.get(i));
                list.remove(i--);
                len = list.size();
                count=0;
            }
            count++;
        }
        cycleCal(list,count); //带着count是为了形成循环,首尾相连
    }
}

第二种方法是用递归解决的,所谓递归呢,就是方法里面调用方法本身的现象。我们在使用递归时不需要明确循环次数,可以很容易的解决一些for循环和while循环很难解决的问题。

注意事项:

1)构造方法不能递归

2)递归次数不能太多,否则就栈内存溢出

3)递归必须有出口 否则就是死递归

接下来就举几个例子来了解一下。

案例一:5的阶乘

public static void main(String[] args) {
    //使用递归求5的阶乘
    System.out.println(fun(5)); //次数不能太多,否则会栈内存溢出
}

public static int fun(int num) {
    if(num == 1) {      //if(num == 1)是递归出口
        return 1;
    }else {
        return num * fun(num - 1);  //调用方法本身
    }
}

案例二:文件遍历

/**
  - 需求:从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名
  - 分析:
  - 从键盘接收一个文件夹路径
  - 1,如果录入的是不存在,给与提示
  - 2,如果录入的是文件路径,给与提示
  - 3,如果是文件夹路径,直接返回
  - 
  - 打印出该文件夹下所有的.java文件名
  - 1,获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
  - 2,遍历数组,对每一个文件或文件夹做判断
  - 3,如果是文件,并且后缀是.java的,就打印
  - 4,如果是文件夹,就递归调用
    */
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);        //创建键盘录入对象
    System.out.println("请输入一个文件夹路径");
    File dir = null;
    while(true) {
        String line = sc.nextLine();        //将键盘录入的文件夹路径存储
        dir = new File(line);       //封装成File对象
        if(!dir.exists()) {
            System.out.println("您录入的文件夹路径不存在,请重新录入");
        }else if(dir.isFile()) {
            System.out.println("您录入的是文件路径,请重新录入文件夹路径");
        }else {
            printJavaFile(dir);
        }
    }   
}

public static void printJavaFile(File dir){
    //获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
    File[] subFiles = dir.listFiles();  
    //有的文件夹 windows系统不让其访问,所以获取某个文件夹里面的所有文件和文件夹,有时候获取成null
    
    //遍历数组,对每一个文件或文件夹做判断
    if(subFiles!=null){ //所以此处需要判断一下获取的subFiles数组是否为null,不判断的话 “for (File subFile : subFiles)” 会报空指针异常
        for (File subFile : subFiles) {
            //3,如果是文件,并且后缀是.java的,就打印
            if(subFile.isFile() && subFile.getName().endsWith(".java")) {
                System.out.println(subFile);

                //4,如果是文件夹,就递归调用
            }else if (subFile.isDirectory()){
                printJavaFile(subFile);
            }
        }
    }
}

了解了约瑟夫问题,是不是觉得数学也能救命了?哈哈。想了解更多学习知识,请关注微信公众号“阿Q说”,获取更多学习资料吧!你也可以后台留言说出你的疑惑,阿Q将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容

  • 今天看了一下约瑟夫问题,嗯,感觉自己智商欠费:( 还是来总结下好啦~ 问题 约瑟夫是犹太军队的一个将军,在反...
    ying_zhang阅读 6,984评论 0 2
  • 原创 猴子选大王 一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从...
    Cipolee阅读 1,505评论 1 3
  • 你从我眼前跑开 像脱缰之马 像越狱之徒 风由此而起 掀起一圈灰尘 太阳把树荫往左移了一下 正好挡住了我追赶的方向 ...
    指茧阅读 381评论 1 9
  • 《七绝·忆同窗》(新韵) 温志龄 粤渝远距忆同窗,岁月蹉跎友谊长。 烽火连天生死共,...
    碧野牧歌阅读 495评论 0 2
  • 亲爱的各位教练团助教以及讲师训的各位战友同学们!大家早上好!为什么说早上好,因为希望咱们早点坐上公司董事位置好不好...
    cindyzhao阅读 1,722评论 0 0