zoukankan      html  css  js  c++  java
  • 《代码大全2》阅读笔记10Chapter 17 Unusual Control Structures

    Chapter 17 Unusual Control Structures
     不常见的控制结构

    17.1 Multiple Returns from a Routine 子程序中的多处返回
    1. 如果能增强可读性,那么就使用return。
    2. 用防卫子句(guard clause)(早返回或早退出)来简化复杂的错误处理
    3. 减少每一个程序中return的数量
     如果在读子程序的后部时,你没有意识到它从前面某个地方返回的可能性,想理解这个子程序就很困难。由此可见,使

    用return要十分谨慎——只当它们能增强可读性的时候才去使用。

    17.2 Recursion 递归
    递归并不常用,但如果使用的谨慎,还是可以得到非常优雅的解。
    递归式是对付复杂事物很有价值的工具——在用于对付适当问题的时候

    ·Example of Recursion 递归的例子
    假设你有一个表示迷宫的数据类型。本质上迷宫是一个网格,在网格上的每一个点,你都可能向上下左右四个方向移动。
    如果用了递归,找到出路会显而易见。你从入口处开始,然后尝试所有可能的路径,直到找到走出去的路来。当你第一次走到某一

    个点上的时候,你试着向左走。如果不能向左走,那么试着向上或者向下,如果还不行,那就向右走了。你不用担心迷路,因为你

    经过某个点的时候,都会在那里留下一些面包屑,所以同一个点是不会走两次的。
    C++示例:用递归穿越迷宫
    bool FindPathThroughMaze( Maze maze, Point position ) {
           //if the position has already been tried, don't try it again.
           if( AlreadyTried( maze, position) ) {
                return false;
           }

           //if the position is the exit, declare success
           if( ThisIsTheExit( maze, position) ) {
                  return true;
           }

           //remember that this position has been tried
           RememberPosition( maze, position );

           //Check the paths to the left, up, down, and to the right; if
           //any path is successful, stop looking
           if( MoveLeft( maze, position, &newPosition ) ) {
                  if(FindPathThroughMaze( maze, newPosition) ) {
                        return true;
                  }
           }

           if( MoveUp( maze, position, &newPosition ) ) {
                  if(FindPathThroughMaze( maze, newPosition) ) {
                         return true;
                  }
           }

           if( MoveDown( maze, position, &newPosition ) ) {
                  if(FindPathThroughMaze( maze, newPosition) ) {
                         return true;
                  }
           }

           if( MoveRight( maze, position, &newPosition ) ) {
                  if(FindPathThroughMaze( maze, newPosition) ) {
                         return true;
                  }
           }
     
           return false;
    }

    1. 第一行代码负责检查这个点有没有尝试过。编写Recursion子程序的关键目标之一就是要防止产生无穷递归。在本例中,如果不

    对某一点是否尝试过进行检查,那么就可能无限地尝试下去。
    2. 第三行语句记得这点已经尝试过了。这将消除因为产生了回环路径而出现无穷递归的可能。

    ·Tips for Using Recursion 使用递归的技巧
    1. 确认递归能够停止

     检查子程序以确认其中含有一条非递归的路径。通常意味着该子程序中含有一项判断,无须进一步递归,就能停下来。
    2. 使用安全计数器防止出现无穷递归
     如果你在一种不允许使用上述简单测试的环境中是用递归,那么就用安全计数器来防止产生无穷递归。
     安全计数器必须是一个不随每次递归调用而重新创建的变量。可以用一个类成员变量,或者把该安全计数器作为参数加

    以传递。
     例如,有时在递归中,假如判断,如果对子程序的调用次数超过了安全上限,递归就会停止。
    3. 把递归限制在一个子程序内
     循环递归(A调用B,B调用C,C调用A)非常危险,因为它很难检查。依靠脑力来管理位于一个子程序内的递归已经够

    困难了;理解跨越多个子程序的递归是在是勉为其难。
    4. 留心栈空间。
     使用递归以后,无法保证你的程序会使用多少栈空间,也很难预测程序在运行期间会表现的怎样。不过,你还是可以按

    下述步骤来控制程序在运行期间的表现。
     首先,如果你使用了安全计数器,那么再给它设置上限的时候,需要考虑的事项之一就是,你愿意给该递归子程序分配

    多少栈空间。把它设置足够低,以防止栈溢出。
     其次,应该注意观察递归函数中局部变量的分配情况,特别要留意那些内存消耗大的对象。
    5. 不要用递归去计算阶乘或者斐波那契数列
     在计算机科学教科书中存在这样的愚蠢的例子来讲解递归。就是计算阶乘或者斐波那契数列。
     用循环去计算阶乘,这很合适。

    总结,在用递归之前你应该考虑它的替换方案。你用递归能做到的,同样也可以使用栈和循环来做到。有时用这种方法好,有时用

    另外一种好。你在定下来使用哪种方法之前,请把两者都考虑一下。

    Key Points 要点
    ·多个return可以增强子程序的可读性和可维护性,同时可以避免产生很深的嵌套逻辑。但是使用它的时候要多加小心。
    ·递归能够优雅地解决一小部分问题。对他的使用也要加倍小心。
    ·在少数情况下,goto是编写可读性和可维护性代码的最佳方法。但是这种情况非常罕见。除非万不得已,不要使用goto。

    Desire has no rest.
  • 相关阅读:
    IEnumerable、ICollection、IList、List关系和区别
    在Winform界面中使用DevExpress的TreeList实现节点过滤查询的两种方式
    关键字Lock的简单小例子
    .NET Core DI简单介绍
    Linux服务器部署.Net Core笔记:六、安装MySQL
    表的透视变换
    ZedGraph怎样在生成曲线时随机生成不一样的颜色
    3、手写Unity容器--第N层依赖注入
    微信支付-小程序H5 公众号 Payment SDK
    WPF继续响应被标记为已处理事件的方法
  • 原文地址:https://www.cnblogs.com/samcn/p/1451330.html
Copyright © 2011-2022 走看看