热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

从约瑟夫问题的递归实现的问题说起

在解决约瑟夫问题时,我比较推荐使用递归,因为递归实现的算法代码更短,逻辑也更清晰,然而很多人有一个疑问,那就是
在解决约瑟夫问题时,我比较推荐使用递归,因为递归实现的算法代码更短,逻辑也更清晰,然而很多人有一个疑问,那就是他们知道递归层数是有极限的,这就意味着当需要很大层数的递归时,递归算法是不可行的,会导致段错误。

        对于这个问题我有三个回答:第一,只要你使用的是计算机而不是你的大脑,你就不要指望什么是无限制的,计算机不是神,计算机里别谈无限。第二,虽然你的c代码是递归实现的,但是编译器生成的二进制文件却不一定会递归调用一个函数,这就涉及了编译器的优化。第三,因为我们使用的大多数是x86体系的冯诺依曼机器,这种机器的编译器一般对于函数调用是通过栈实现的,而我们知道栈的预备空间和最大扩展空间一般都不会太大,然而如果有一种机器,根本就没有栈的概念,或者说即使在x86机器上实现一个变态的编译器,将函数调用退化成简单的jump而不使用栈操作,那么栈的限制将不再存在。

        在基于栈实现函数调用的机器上,我们看一下在什么情况下必须层层嵌套用递归实现。其中一个条件,那就是在递归的过程中,我们无法获知任何计算的中间结果,必须等到最深入一层的函数满足非递归条件而返回时,整个过程才会一层一层的返回,但是如果每一步的中间结果都被保存或者说每一步的递归过程并不是要计算什么值,而仅仅是为了实现一个副作用,那么最终的二进制文件大可不必非要用递归。而且我们知道,递归和迭代是等价的,这一点非常重要。

        编译器不是傻子-其实是实现编译器的人很聪明,编译器一定不会傻到非要用递归生成最终的二进制执行文件,以gcc为例,即使你在c函数中明确使用了递归,在-O3的优化编译选项下,编译器还是会尝试将递归化为迭代的,所生成的二进制objdump文件中你将看不出任何递归调用,这种工作并不是你自己实现的,而是编译器帮你实现的。

        有一种递归被叫做“尾递归”,对于这种递归的理解其实很简单,那就是每一步递归调用的中间结果被保存,因此你可以只使用一个栈帧实现所有的递归过程,因为中间结果随着递归的深入而持续改变,因此你可以将其理解为一种隐含的迭代。对于约瑟夫问题,这种尾递归是很显然的,因为每一步的递归过程的效果其实都是一种副作用,那就是在链表上删除一个节点。但是你还是要告诉编译器这一切,否则编译器仍然使用递归过程生成二进制代码。

        最终的结果,你用-O3选项编译这个c文件,使用objdump查看其目标码,你将看不到任何递归过程,这就突破了栈的限制,但是记住,限制仍然是有的,因为很抱歉,你用的是计算机这种奴隶式的工具,计算机说的最多的话,那就是:Sorry, it is beyond my ablity!






推荐阅读
  • 【技术分享】一个 ELF 蠕虫分析
    【技术分享】一个 ELF 蠕虫分析 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 在2022年,随着信息化时代的发展,手机市场上出现了越来越多的机型选择。如何挑选一部适合自己的手机成为了许多人的困扰。本文提供了一些配置及性价比较高的手机推荐,并总结了选择手机时需要考虑的因素,如性能、屏幕素质、拍照水平、充电续航、颜值质感等。不同人的需求不同,因此在预算范围内找到适合自己的手机才是最重要的。通过本文的指南和技巧,希望能够帮助读者节省选购手机的时间。 ... [详细]
  • 本文记录了作者对x265开源代码的实现与框架进行学习与探索的过程,包括x265的下载地址与参考资料,以及在Win7 32 bit PC、VS2010平台上的安装与配置步骤。 ... [详细]
  • 在win8上安装SQL2000的详细步骤(原创)
    本文详细介绍了在win8操作系统上安装SQL2000的步骤,包括找到安装文件、设置兼容性、输入序列号、选择数据库路径、选择账号模式、输入密码、处理错误提示等。适用于那些想在win8上使用SQL2000的用户。 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 通过Anaconda安装tensorflow,并安装运行spyder编译器的完整教程
    本文提供了一个完整的教程,介绍了如何通过Anaconda安装tensorflow,并安装运行spyder编译器。文章详细介绍了安装Anaconda、创建tensorflow环境、安装GPU版本tensorflow、安装和运行Spyder编译器以及安装OpenCV等步骤。该教程适用于Windows 8操作系统,并提供了相关的网址供参考。通过本教程,读者可以轻松地安装和配置tensorflow环境,以及运行spyder编译器进行开发。 ... [详细]
  • 第四讲ApacheLAMP服务器基本配置Apache的编译安装从Apache的官方网站下载源码包:http:httpd.apache.orgdownload.cgi今 ... [详细]
  • 原文地址http://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/最开始时 ... [详细]
  • centos6.8 下nginx1.10 安装 ... [详细]
author-avatar
BBCong
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有