5-语句编写的技巧与设计

来源:互联网 发布:三菱gxworks2软件下载 编辑:程序博客网 时间:2024/06/05 03:16

5-语句编写的技巧与设计

5.1 顺序性语句

5.1.1 有明确顺序的语句

  1. 设法组织代码,使依赖关系变得非常明显
  2. 使子程序名能凸显依赖关系
  3. 利用子程序参数明确显示依赖关系
  4. 用注释对依赖关系进行说明
  5. 用断言或者错误处理检查依赖关系

5.1.2 顺序无关的语句

  1. 不要跳来跳去
  2. 把相关的语句组织在一起
    image
    image

5.2 条件语句

5.2.1 使用条件语句

  • 在代码中条件语句用来控制其它语句是否执行
  • 常见的条件语句形式
    if-then
    if-then-else
    switch-case

5.2.2 if-then-else使用原则

  • 主要原则:首先写正常代码路径, 再处理不常见情况

    1. 确保对于等量的分支是正确的– 即>= 和 <= 的边界值误差(off-by-one)
    2. 把正常情况的处理放在if 后面而不要放在else后面– 把决策的结果代码放在尽可能靠近决策位置
    3. 让if子句后面跟随一个有意义的语句
    4. 严格的else搭配
  • 思想:把决策的结果代码放在尽可能靠近决策位置

  • 所谓正常的处理情况指的是程序运行的最主要路径
  • 将注意力集中在正常路径上便于设计分支的逻辑

image

  • 以上示例代码的问题在于:
    1. 从理解代码的角度来看,难以辨识程序的正常路径
    2. 从编写代码的角度来看,难以设计分支逻辑
  • 调整的策略
    1. 正常的路径一致地写在前面,即if语句后面
    2. 所有的错误情况都写在后面,即else语句后面

image

5.2.3 调用布尔函数简化复杂判断

  • 复杂的判断情况会影响代码的可读性
  • 将复杂的判断从代码中隔离开
  • 通过布尔函数封装判断过程

image
image

5.2.4 把最常见的情况放在最前面并确保所有情况都被考虑到

image
image

5.2.5 小心使用switch

  • 简化每种情况对应的操作
  • 不要为了使用case语句而刻意制造一个变量
    image
    image

  • 把default子句只用于检查真正默认的情况

  • 利用default子句来检测错误
    image
  • 避免代码执行越过一条case子句的末尾
    image

5.3 控制循环语句

5.3.1 循环类型

  • 计数循环( counted loop ):执行的总次数是一定的
  • 连续求值的循环( continuously evaluated loop ):预先并不知道将要执行多少次,它会在每次送代时检查是否应该结束
  • 无限循环(end less loop)
  • 迭代器循环( iterator loop):对容器类里面的每个元素执行一次操作

Java

image

C++

image

// equivalent loop using iterators to reset all the elements in ivec to 0for (vector<int>::iterator iter = ivec.begin();        iter != ivec.end(); ++iter)    *iter = 0; // set element to which iter refers to 0int main(){    std::vector<uint32_t> vec;    // Nice and succinct, use generate_n to generate 10,000,000    // values with the Increment generator    std::generate_n(back_inserter(vec), 10000000, Increment(0));    for (int i = 0; i < 1000; ++i) {        //Sum and output the values of each vector.            std::cout << std::for_each(vec.begin(), vec.end(), Sum()).m_sum <<std::endl;    }}

5.3.2 循环灵活度和位置检查

  • 循环的灵活度
    1. 循环执行的次数是严格设定好的
    2. 每次选代的时候检查循环有没有完成
  • 检查位置
    1. 检查循环是否执行完毕的位置分开始、中间和结尾
    2. 如果是在循环头进行检查,那么其循环体就不一定会执行到
    3. 如果把检查放在循环尾,则循环体就会至少执行一次
    4. 如果是在循环的中间检查,那么位于检查前面的那部分循环就会至少执行一次,但是其后的那部分循环就不一定会执行

5.3.3 带退出的循环的使用

  • 使用场景
    1. 如果把循环条件检测放在循环开始或结束处,那就需要写出一个半循环(loop-and-a-half)的代码。
    2. 所谓半循环的代码就是为了完成整个循环而设置在循环体之外的部分

image
image

5.3.4 带退出循环的注意事项

  • 把所有的退出条件放在一处
    1. 多个退出条件分散在不同位置,会使得某些终止条件在调试、修改或者测试的时候被忽略。
  • 用注释来阐明操作意图
    1. 如果在一个不直接支持带退出循环的语言里使用直接退出法,那么就应该用注释把要做的事情解释清楚。

5.3.5 循环控制–循环容易出现的错误

  • 忽略或错误地对循环执行初始化
  • 忽略了对累加变量或其他与循环有关的变量执行初始化
  • 不正确的嵌套
  • 不正确的循环终止
  • 忽略或者错误地增加了循环变量的值
  • 用不正确的循环下标访问数组元素

5.3.6 设计循环控制的理念

  • 使循环尽量模块化:应该把循环看做是一个黑盒子:外围程序只知道它的控制条件,却不知道它的内容。
  • C++示例:将循环视为黑盒子
    while ( !inputFile.EndOfFile() && moreDataAvailable ) {
    }

5.3.7 从三个方面考虑循环

如何进入循环

  • 只从一个位置进入循环:goto语句的使用可能破坏这个原则
  • 把初始化代码紧放在循环前面:把循环初始化语句和与它相关的循环放在一起
  • 用while(true)表示无限循环:C++、 Java 、 Visual Basic 中无限循环的标准写法;用for ( ; ; ) 也是一种可以接受的写法
  • 在适当的情况下多使用for 循环:for循环的优点是把循环的控制代码集中在一处,从而有助于写成可读性强的循环;注意:当循环的控制部分较为复杂的时候,for循环未必是好的选择
  • 在while 循环更适用的时候,不要使用for 循环:当循环的控制部分较为复杂的时候,可以考虑使用 while循环
    image
    image
    image

处理好循环体

  • 明确循环体的部分:用“ {” 和“ } ” 把循环中的语句括起来,一个循环只做一件事;循环应该和子程序一样, 每个循环只做一件事并且把它做好
  • 避免空循环
    image
  • 把循环内务操作(housekeeping,内部管理)要么放在循环的开始,要么放在循环的末尾

如何退出循环

  • 设法确认循环能够终止
  • 使循环终止条件看起来很明显
  • 不要为了终止循环而胡乱改动for 循环的下标
  • 避免出现依赖于循环下标最终取值的代码
  • 在循环终止后使用循环下标值是很不好的习惯
    1. 循环下标的最终取值根据语言以及实现的不同而具有微妙差异
    2. 更好并且更具自我描述性的做法是,在循环体内 某个适当的地方把这一最终取值赋给某个变量
      image
      image

5.4 特殊的控制结构

有一些特殊的控制结构是编程中的双刃剑
- 不是所有语言都有的, 但如果提供,需谨慎地使用它们
- 子程序中的多处返回
- 递归
- Goto

5.4.1 子程序的多处返回

  • 程序可以通过return 和exit这类控制结构,在任何需要的时候退出子程序
  • 子程序按照正常的退出途径终止, 并把控制权转交给调用方子程序

5.4.2 使用return语句的指导原则

image

  • 用防卫子句( guard clause) ( 早返回或早退出) 来简化复杂的错误处理:如果代码中必须要在执行正常操作之前做大量的错误条件检测, 就很可能导致代码的缩进层次过深,并且遮蔽正常情况的执行路径

image
image
image

5.4.3 递归使用情形

  • 一个子程序自己负责解决某个问题的一小部分,它还把问题分解成很多的小块,然后调用自己来分别解决每一小块
  • 当问题的小部分很容易解决,而问题的大部分也很容易分解成众多的小部分时,常常会用到递归
    image

5.4.4 使用递归的技巧

  • 确认递归能够停止
    1. 检查子程序以确认其中含有一条非递归的路径
    2. 通常这意味着该子程序中含有一项判断,无须进一步递归就能停下来
  • 使用安全计数器防止出现无穷递归
    1. 安全计数器来防止产生无穷递归
    2. 该安全计数器必须是一个不随每次子程序调用而重新创建的变量
      image

5.4.5 避免循环递归

  • 循环递归形 如A调用B , B调用C, C调用A
  • 将递归限制在一个子程序中以避免出现循环递归
  • 如果无法避免循环递归的话,可以使用安全计数器来防止出现无穷递归

5.4.6 GOTO语句

  • GOTO是一种无条件跳转语句
  • GOTO可能是目前程序设计语言中最受争议的机制之一
  • 含有goto 的代码很难安排好格式
  • 使用goto 也会破坏编译器的优化特性
  • 使用goto 会使运行速度更慢,而且代码也更大
  • 如果使用位置恰当, goto可以减少重复的代码
  • goto在分配资源、使用资源后再释放资源的子程序里非常有用
  • 在某些情况下,使用goto 会让代码的运行速度更快,体积更小
  • 大部分论断都反对随意使用goto

image
image
image
image

5.5 表驱动法

  • 表驱动法是一种编程模式(scheme), 从表里面查找信息而不使用逻辑语句(if和case)
  • 表驱动法适用于复杂的逻辑
  • 表驱动法的另一个好处是可以将复杂逻辑从代码中独立出来,以便于单独维护

image

5.5.1 表驱动的问题

  • 在表里存放什么信息:主要存放的是数据,但在一些特殊情况下也存放动作
  • 如何快速从表中查询条目
    1. 直接访问(Direct access)
    2. 索引访问(Indexed access)
    3. 阶梯访问(Stair-step access)

5.5.2 直接访问

所谓“直接访问”是指通过索引值(如下标)可以直接从表中找到对应的条目

image

  • 编写一个子程序,打印存储在一份文件中的消息
    1. 通常该文件中会存储大约500 条消息,而每份文件中会存有大约20种不同的消息。这些消息源自于一些浮标( Buoy) ,提供有关水温、浮标位置等信息。
    2. 每一条消息都有若干字段,并且每条消息都有一个消息头,其中有一个ID ,告诉该消息属于这20多种消息中的哪一种。
    3. 这些消息的格式并不是固定不变的

image
image

基于逻辑的方法

  • 读取每一条消息,检查其ID,然后调用一个用来阅读、解释以及打印一种消息的子程序
  • 消息阅读子程序包含一个循环,用来读入消息、解释其ID,以及根据该ID调用20 个子程序中的某一个
  • 如果你有20种消息,那么就要有20个子程序
  • 每次有任何一种消息的格式变了,就不得不修改负责处理该消息的子程序或者类的逻辑

image

面向对象的方法

问题的逻辑可隐藏在对象继承结构里,但是基本结构还是同样复杂

image
image

表驱动法

  • 消息阅读子程序由一个循环组成,该循环负责读入每一个消息头,对其ID解码,在Message 数组中查询其消息描述,然后每次都调用同一个子程序来解释该消息
  • 只需要用一张表来描述每种消息的格式,而不用再把它们硬编码进程序逻辑里
    image
    image
    image
    image

5.5.3 索引访问表

  • 当无法直接从表中查询需要的条目时,就需要借助其他办法先获取表键值
  • 索引访问的方法就是先用一个基本类型的数据从一张索引表中查出一个键值,然后再用这一键值查出相应的主数据
  • 索引表是一种间接访问的技术

  • 假设经营着一家商店,大约100 种商品。 再假设每种商品都有一个4 位数字的物品编号, 其范围是0000 到9999

  • 如果想用这个编号作为键值直接查询(直接访问表)一张描述商品信息的表,那么就要生成一个具有10000 条记录的访问表(中间有很多空着的)

使用索引访问表

  • 如果用这个编号作为键值直接查询一张描述商品信息的表,那么就生成一个具有10000 条记录的索引数组(从0到9999)
  • 该数组中除了与商店中的货物的标志相对应的100条记录以外,其余记录都是空的

image

优点

  • 如果主查询表中的每一条记录都很大,那么索引数组就可以节省很多空间: 一般而言索引表中的每条记录需要占用2~4字节
  • 即使用了索引以后没有节省内存空间, 操作位于索引中的记录有时也要比操作位于主表中的记录更方便更廉价
  • 编写到表里面的数据比嵌入代码中的数据更容易维护

5.5.4 阶梯访问表

阶梯访问方法不像索引结构那样直接, 但是它要比索引访问方法节省空间

image

  • 使用阶梯法

  • 把每一区间的上限写入一张表里, 然后写一个循环,按照各区间的上限来检查分数

    1. 当分数第一次超过某个区间的上限时, 就知道相应的等级了
    2. 区间表:{ 50.0, 65.0, 75.0, 90.0, 100.0 }
      image

5.6 一般控制性问题

5.6.1 布尔表达式

理解布尔表达式是如何求值的

  • 一些语言的编译器会先计算布尔表达式中的每个项的值,然后再把这些项组合起来求出整个表达式的值
  • 一些语言的编译器采用“ 短路(short-circuit ) ”或者“惰性(lazy)”求值, 只求出那些必须的部分
    image

易错的判断

  • 如果整个表达式都被求值,就会在循环的最后一次迭代中遇到一个错误
  • 由于变量i 等于MAX_ELEMENTS,所以表达式item[i]就等于item [MAX_ELEMENTS] ,而这是一个数组下标越界错误
  • 在C++、 Java等语言中就可以回避掉此类错误

  • Java示例:利用短路求值的判断

    if ( ( denominator ! = 0 ) && ( ( item / denominator ) > MIN_VALUE ) )

  • 如果在denominator 等于0 的时候求整个表达式的值,那 么位于第二个操作数处的除法就会产生一个除零错误。

  • 由于仅当第一部分为真的时候才去求第二个部分的值,因 此当denominator 等于0 的时候第二部分就不会参与计算 了,因此就不会产生除零错误。

5.6.2 复合语句(语句块)

  • “ 复合语句”或“语句块”指的是一组语旬,该组语句被视为一条单一的语句,用于控制程序流
    1. 在C++ 、 C#、 C 和Java 中,可以通过在一组语句的外面括上“{”和“}”来创建复合语句
    2. 把括号对一起写出
    3. 用括号来把条件表达清楚

5.6.3 深层嵌套

避免方法

  • 重复判断一部分条件

    1. 通过重复检测条件中的某一部分来简化嵌套的 if 语句
    2. 并非多重嵌套 if语句就一定需要简化, 简化的原则是能否清晰的理解多重嵌套的代码
    3. 注:有效利用强调主要路径的方法也可以使多重嵌套语句易于理解
      image
      image
  • 转换成if-then-else

    1. 把嵌套的if结构转换成一组if-then-else 语句
    2. 如果if结构嵌套的较深, 则有可能是因为逻辑组织的不好并非逻辑判断本身设计的不好,而是代码反映该逻辑判断的组织结构不好
    3. 多重 if嵌套转换为一组if-then-else 语句,并不是对逻辑判断的重新组织
      image
      image
  • 转换成case 语句
    1. 如果语言支持case语句的话,尝试将多重if嵌套改写为case语句
    2. 对于含有整型、字符以及枚举的判断使用case尤为有效
      image
      image
      image
  • 把深层嵌套的代码提取成单独的子程序

    1. 如果深层嵌套出现在循环里, 通常都可以通过把循环体提取成子程序来加以改善
    2. 当嵌套是由于条件和迭代二者共同产生的时候, 这种做法将特别有效
    3. 具体做法: 把if-then-else 分支保留在主循环中, 以便显示决策的分支, 然后把分支中的语句提取成单独的子程序。
  • 使用对象和多态派分( polymorphic dispatch )

    1. 使用面向对象的技术来简化该代码的方法是使用不同的类来封装不同的子程序
    2. 在此基础上可以考虑使用多态或接口的技术,即构造相应的类继承或接口实现体系来管理封装的子程序
      image

5.7 结构化编程

5.7.1 三种基本结构

  • 顺序(Sequence)“ 顺序” 指一组按照先后顺序执行的语句。
  • 选择(Selection)选择是一种有选择的执行语旬的控制结构。 if-thenelse,case
  • 迭代(Iteration)迭代是一种使一组语句多次执行的控制结构,常称为“循环”。

5.7.2 控制结构与复杂度

控制结构之所以受到了如此多的关注,就是因为它们对程序整体复杂度的影响非常大

  • Tom McCabe认为选择和迭代的数量和程序复杂性成正比
  • 决策点(decision point)度量法
    image
    image

1. 小结

1.1 条件语句

  • 优先考虑正常代码路径

    1. 能够根据此原则对代码进行优化调整(难度限于CC2和PPT)
    2. 把正常情况的处理放在if后面而不要放在else后面
  • 利用布尔函数调用简化复杂的检测

    1. 能够根据此原则对代码进行优化调整(难度限于CC2和PPT)
    2. 复杂的判断情况会影响代码的可读性;将复杂的判断从代码中隔离开;通过布尔函数封装判断过程
  • 主要原则:首先写正常代码路径, 再处理不常见情况

    1. 确保对于等量的分支是正确的– 即>= 和 <= 的边界值误差(off-by-one)
    2. 把正常情况的处理放在if 后面而不要放在else后面– 把决策的结果代码放在尽可能靠近决策位置
    3. 让if子句后面跟随一个有意义的语句
    4. 严格的else搭配
  • 思想:把决策的结果代码放在尽可能靠近决策位置

  • 所谓正常的处理情况指的是程序运行的最主要路径
  • 将注意力集中在正常路径上便于设计分支的逻辑

image

  • 以上示例代码的问题在于:
    1. 从理解代码的角度来看,难以辨识程序的正常路径
    2. 从编写代码的角度来看,难以设计分支逻辑
  • 调整的策略
    1. 正常的路径一致地写在前面,即if语句后面
    2. 所有的错误情况都写在后面,即else语句后面

image

1.1.1 调用布尔函数简化复杂判断

  • 复杂的判断情况会影响代码的可读性
  • 将复杂的判断从代码中隔离开
  • 通过布尔函数封装判断过程

image
image

1.1.2 把最常见的情况放在最前面并确保所有情况都被考虑到

image
image

1.1.3 小心使用switch

  • 简化每种情况对应的操作
  • 不要为了使用case语句而刻意制造一个变量
    image
    image

  • 把default子句只用于检查真正默认的情况

  • 利用default子句来检测错误
    image
  • 避免代码执行越过一条case子句的末尾
    image

1.2 循环

1.2.1 循环类型

  • 计数循环( counted loop ):执行的总次数是一定的
  • 连续求值的循环( continuously evaluated loop ):预先并不知道将要执行多少次,它会在每次送代时检查是否应该结束
  • 无限循环(end less loop)
  • 迭代器循环( iterator loop):对容器类里面的每个元素执行一次操作

1.2.2 带退出的循环的使用

  • 能够使用带退出循环对带半循环的代码进行改写
  • 半循环部分的代码在修改时要保持一致
  • 带退出循环对带半循环的代码改写

  • 使用场景

    1. 如果把循环条件检测放在循环开始或结束处,那就需要写出一个半循环(loop-and-a-half)的代码。
    2. 所谓半循环的代码就是为了完成整个循环而设置在循环体之外的部分

image
image

1.2.3 从三个方面考虑循环

如何进入循环

  • 只从一个位置进入循环:goto语句的使用可能破坏这个原则
  • 把初始化代码紧放在循环前面:把循环初始化语句和与它相关的循环放在一起
  • 用while(true)表示无限循环:C++、 Java 、 Visual Basic 中无限循环的标准写法;用for ( ; ; ) 也是一种可以接受的写法
  • 在适当的情况下多使用for 循环:for循环的优点是把循环的控制代码集中在一处,从而有助于写成可读性强的循环;注意:当循环的控制部分较为复杂的时候,for循环未必是好的选择
  • 在while 循环更适用的时候,不要使用for 循环:当循环的控制部分较为复杂的时候,可以考虑使用 while循环
    image
    image
    image

处理好循环体

  • 明确循环体的部分:用“ {” 和“ } ” 把循环中的语句括起来,一个循环只做一件事;循环应该和子程序一样, 每个循环只做一件事并且把它做好
  • 避免空循环
    image
  • 把循环内务操作(housekeeping,内部管理)要么放在循环的开始,要么放在循环的末尾

如何退出循环

  • 设法确认循环能够终止
  • 使循环终止条件看起来很明显
  • 不要为了终止循环而胡乱改动for 循环的下标
  • 避免出现依赖于循环下标最终取值的代码
  • 在循环终止后使用循环下标值是很不好的习惯
    1. 循环下标的最终取值根据语言以及实现的不同而具有微妙差异
    2. 更好并且更具自我描述性的做法是,在循环体内 某个适当的地方把这一最终取值赋给某个变量
      image
      image

1.2.4 使用return语句的指导原则

image

  • 用防卫子句( guard clause) ( 早返回或早退出) 来简化复杂的错误处理:如果代码中必须要在执行正常操作之前做大量的错误条件检测, 就很可能导致代码的缩进层次过深,并且遮蔽正常情况的执行路径

image
image
image

1.3 GOTO

  • 了解goto机制的背景和应用原则

  • Dijistra最早提出批评:“Goto是有害的”。一个程序的易读性和以理解性同其中所包含的无条件转移控制的个数成反比例;转移语句的个数越多,程序就越难读、难懂。

  • 含有goto的代码很难安排好格式
  • 使用goto也会破坏编译器的优化特性
  • 使用goto会使运行速度更慢,而且代码也更大

  • 支持GOTO的观点:

  • 如果使用位置恰当,goto可以减少重复的代码
  • goto在分配资源、使用资源后再释放资源的子程序里非常有用
  • 在某些情况下,使用goto会让代码的运行

1.4 表驱动法(重要)(难度限于CC2和PPT)

  • 掌握直接访问、索引访问和阶梯访问的概念,能够:
    1. 判断代码中使用的表驱动技术属于哪一种
    2. 理解代码中“表”的定义和使用
    3. 其中重点掌握直接访问表、索引访问表

表驱动是一种编程模式,适用于复杂的逻辑,可以将复杂逻辑从代码中独立出来,以便于单独维护。

表驱动法:消息阅读子程序由一个循环组成,该循环负责读入每一个消息头,对其ID解码,在Message 数组中查询其消息描述,然后每次都调用同一个子程序来解释该消息只需要用一张表来描述每种消息的格式,而不用再把它们硬编码进程序逻辑里定义

使用

  • 直接访问:指通过索引值可以直接从表中找到对应的条目。
  • 索引访问:是一种间接访问技术,就是先用一个基本类型的数据从一张索引表中查处一个键值,然后再用这一键值查处你感兴趣的主数据。
  • 索引访问技术优点:如果主查询表中的每一条记录都很大,那么索引数组就可以节省很多空间;即使你用了索引以后没有节省内存空间,操作位于索引中的记录有时也要比操作位于主表中的记录更方便更廉价;便写道表里面的数据比嵌入式代码中的数据更容易维护。
  • 阶梯访问:更节省空间,通过确定每项命中的阶梯层次确定其归类。
    Eg. 把每一区间的上限写入一张表里,然后写一个循环,按照各区间的上限来查分数。当分数第一次超过某个区间的上限时,你就知道相应的等级了。

5.5 表驱动法

  • 表驱动法是一种编程模式(scheme), 从表里面查找信息而不使用逻辑语句(if和case)
  • 表驱动法适用于复杂的逻辑
  • 表驱动法的另一个好处是可以将复杂逻辑从代码中独立出来,以便于单独维护

image

5.5.1 表驱动的问题

  • 在表里存放什么信息:主要存放的是数据,但在一些特殊情况下也存放动作
  • 如何快速从表中查询条目
    1. 直接访问(Direct access)
    2. 索引访问(Indexed access)
    3. 阶梯访问(Stair-step access)

5.5.2 直接访问

所谓“直接访问”是指通过索引值(如下标)可以直接从表中找到对应的条目

image

  • 编写一个子程序,打印存储在一份文件中的消息
    1. 通常该文件中会存储大约500 条消息,而每份文件中会存有大约20种不同的消息。这些消息源自于一些浮标( Buoy) ,提供有关水温、浮标位置等信息。
    2. 每一条消息都有若干字段,并且每条消息都有一个消息头,其中有一个ID ,告诉该消息属于这20多种消息中的哪一种。
    3. 这些消息的格式并不是固定不变的

image
image

表驱动法

  • 消息阅读子程序由一个循环组成,该循环负责读入每一个消息头,对其ID解码,在Message 数组中查询其消息描述,然后每次都调用同一个子程序来解释该消息
  • 只需要用一张表来描述每种消息的格式,而不用再把它们硬编码进程序逻辑里
    image
    image
    image
    image

5.5.3 索引访问表

  • 当无法直接从表中查询需要的条目时,就需要借助其他办法先获取表键值
  • 索引访问的方法就是先用一个基本类型的数据从一张索引表中查出一个键值,然后再用这一键值查出相应的主数据
  • 索引表是一种间接访问的技术

  • 假设经营着一家商店,大约100 种商品。 再假设每种商品都有一个4 位数字的物品编号, 其范围是0000 到9999

  • 如果想用这个编号作为键值直接查询(直接访问表)一张描述商品信息的表,那么就要生成一个具有10000 条记录的访问表(中间有很多空着的)

使用索引访问表

  • 如果用这个编号作为键值直接查询一张描述商品信息的表,那么就生成一个具有10000 条记录的索引数组(从0到9999)
  • 该数组中除了与商店中的货物的标志相对应的100条记录以外,其余记录都是空的

image

优点

  • 如果主查询表中的每一条记录都很大,那么索引数组就可以节省很多空间: 一般而言索引表中的每条记录需要占用2~4字节
  • 即使用了索引以后没有节省内存空间, 操作位于索引中的记录有时也要比操作位于主表中的记录更方便更廉价
  • 编写到表里面的数据比嵌入代码中的数据更容易维护

5.5.4 阶梯访问表

阶梯访问方法不像索引结构那样直接, 但是它要比索引访问方法节省空间

image

  • 使用阶梯法

  • 把每一区间的上限写入一张表里, 然后写一个循环,按照各区间的上限来检查分数

    1. 当分数第一次超过某个区间的上限时, 就知道相应的等级了
    2. 区间表:{ 50.0, 65.0, 75.0, 90.0, 100.0 }
      image
0 0
原创粉丝点击