表驱动法(Table-Driven Methods)

2023-10-29

背景

表驱动方法是一种方案,它允许您在表中查找信息,而不是使用逻辑语句(if和 case)来查明信息。实际上,您可以使用逻辑语句选择的任何内容,都可以使用表进行选择。在简单情况下,逻辑语句更容易,更直接。随着逻辑链变得越来越复杂,表格变得越来越有吸引力。

当使用表驱动方法时,必须解决两个问题。首先,您必须解决如何在表中查找条目的问题。您可以使用一些数据直接访问表。例如,如果您需要按月对数据进行分类,则键入月表很简单。您可以使用索引为1到12的数组。

但当其他数据太笨拙,则无法用于直接查找表条目。例如,如果需要按社会保险号分类数据,则除非可以负担在表中存储999-99-9999的条目,否则就不能直接使用社会保险号直接键入表中。您被迫使用更复杂的方法。以下是在表中查找条目的方法的列表:

  • 直接访问
  • 索引访问
  • 阶梯访问

在选择表驱动法的时候,需要解决的第二个问题是,你应该在表里面存些什么。有的时候,表查询出来的结果是数据。如果你遇到的是这种情况,那么就可以把这些数据保持到表里面。在另外一些情况下,表查询出来的结果是动作(action)。在这种情况下,你可以保持一个描述该动作的代码,或者,在有些语言里,你可以保存对实现该动作的子程序的引用。无论是哪一种情况,表都会变得更为复杂

直接访问表

像所有查找表一样,直接访问表取代了更复杂的逻辑控制结构。它们是“直接访问”,因为您不必跳过任何复杂的步骤即可在表中查找所需的信息。
在这里插入图片描述

示例

假设您需要确定每月的天数(暂是不考虑平/润年)。当然,一种笨拙的方法是编写一个大型的if语句:

if ( month = 1 ) 
   days = 31
else if ( month = 2 ) 
   days = 28
else if ( month = 3 ) 
   days = 31
else if ( month = 4 )
   days = 30
else if ( month = 5 ) 
   days = 31
else if ( month = 6 ) 
   days = 30
else if ( month = 7 ) 
   days = 31
else if ( month = 8 ) 
   days = 31
else if ( month = 9 ) 
   days = 30
else if ( month = 10 )
   days = 31
else if ( month = 11 ) 
   days = 30
else if ( month = 12 ) 
   days = 31 End If

执行相同功能的一种更容易且更可修改的方法是将数据放入表中。

int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
days = months[month -1];

上面第一个例子很好理解,很快就能编写。但当你数组下标索引是不规律的时候呢?例如:

假设你在写一个保险费率的程序,这个费率会根据年龄、性别、婚姻状态等不同情况变化,如果你用逻辑控制结构(if、switch)来表示不同费率,那么会非常麻烦。

if ( gendar == Male )
{
        if ( maritalStatus == Single )
        {
                if ( age < 18 )
                {
                        rate = 80.00;
                }
                else if ( age < 30 )
                {
                        rate = 90.00;
                }
                //.......其他略
        }
        else if ( maritalStatus == Maried )
        {
                //又是一串年龄判断分支
        }
}
else if ( gendar == Female )
{
        //又是一串婚姻状况判断分支
}

但是从上面的日历例子来看,这个年龄却是个范围,不是个固定的值,没法用数组或者对象来做映射,那么该怎么办呢?这里涉及到了上面说的问题,如何从表中查询?
这个问题可以用阶梯访问表和直接访问表两种方法来解决,阶梯访问这个后续会介绍,这里只说直接访问表。

有两种解决方法:

  1. 复制信息从而能够直接使用键值

    我们可以给1-17年龄范围的每个年龄都复制一份信息,然后直接用age来访问,同理对其他年龄段的也都一样。这种方法在于操作很简单,表的结构也很简单。但有个缺点就是会浪费空间,毕竟生成了很多冗余信息。

  2. 转换键值以使其能够直接使用

    我们不妨再换种思路,如果我们把年龄范围转换成键值呢?这样就可以直接来访问了,唯一需要考虑的问题就是年龄如何转换为键值。
    我们当然可以继续用if else完成这种转换。前面已经说过,简单的if else是没什么问题的,表驱动只是为了优化复杂的逻辑判断,使其变得更灵活、易扩展。

  3. 将键值转换提取成独立的子程序

    如果你必要构造一些数据让它们像表键值一样使用,那么就把数据到键值的转换提取到独立的子程序。这么做可以避免在不同位置执行了不同的转换,也使得转换操作修改起来更加容易。

typedef enum gender
{
	 Man,
	 Woman
}Gender;

typedef enum marrialstatus
{
	 Single,
	 Married
}MaritalStatus;

typedef enum smokingstatus
{
	 Smoking,
	 NoSmoking
}SmokingStatus;

//表驱动法来代替多判断语句
//可通过赋值、读入数据等方式来进行表初始化
typedef std::map<Gender, std::map<MaritalStatus, std::map<SmokingStatus, double> > > RATETABLE;
static RATETABLE rateTable;

void InitRateTabel()
{
	 rateTable[Man][Single][Smoking] = 20.8;
	 rateTable[Man][Single][NoSmoking] = 18.2;
	 rateTable[Man][Married][Smoking] = 20.0;
	 //...初始化
}

索引访问表

有时,简单的数学转换功能不足以使从Age等数据跳转到表键。一些这样的情况适合于索引访问方案的使用。

使用索引时,可以使用主数据在索引表中查找键,然后使用索引表中的值查找您感兴趣的主数据。

假设您经营一个仓库,库存约为100件。进一步假设每个项目都有一个四位数的部件号,范围从0000到9999。在这种情况下,如果要使用部件号直接键入描述每个项目某些方面的表,需设置一个索引包含10,000个条目(从0到9999)的数组。除与仓库中100个物料的零件号相对应的100个条目外,其余数组将为空,这造成了大量空间的浪费。
在这里插入图片描述
在用一个简单方法无法将“英文单词”这样数据转换成表下标时,可以考虑使用索引来查找.在.net中的Dictionary<K,V> 就是一个典型的例子。

使用索引查询的主要优点就是代码的可读性大为增强,可维护性也更好。使用分段查找,
分段查找通过确定数据所处的范围确定分类(下标)

struct
{
    int key;
    string strdata;
}arr_datas[]={
    {1,"this is one"},
    {2,"this is two"},
    {3,"this is three"},
};
for (i = 0; i < 3; i++)
{
    if (arr_datas[i].key == val)
    {
        return arr_datas[i].strdata;
    }
}

使用分段查找,需要先把每一个区间的上限写在一个表中,然后通过循环确定所处的区段,最后获得相应的等级。

有人可能想到用stl的map,查找速度会快一些,不过想到定义一个map,然后调用一堆insert其实也挺麻烦的,而且例子中用的是int,但是并不是所有的类型都是可hash的,所以有些情况下map并不能胜任。

阶梯访问表

一种表访问方式是阶梯方法。这种访问方法不像索引结构那样直接,但是它不会浪费太多的数据空间。

如图18-5所示,阶梯结构的总体思想是,表中的记录对于不同的数据范围有效,而不是对不同的数据点有效。
在这里插入图片描述
例如,如果您正在编写评分程序,则“ B”输入范围可能从75%到90%。您可能有一天需要编程编制以下一系列成绩:

范围 评分
≥ 90.0% A
< 90.0% B
< 75.0% C
< 65.0% D
< 50.0% E

这可能直接访问有点问题,因为您不能使用 简单的数据转换功能 来 映射字母A到F。而索引方案会很尴尬,因为数字是浮点数。 您可能考虑将浮点数转换为整数,在这种情况下,这将是一个有效的设计选项,但是为了说明起见,本示例将坚持使用浮点数。

要使用阶梯方法,您需要将每个范围的最大值放入表格中,然后编写一个循环以对照每个范围的最大值检查分数。 当您发现分数首次超过范围最高点时,您就知道分数是多少。 使用阶梯技术时,您必须小心地正确处理范围的端点。

  double rangeLimit[] = {50.0, 65.0, 75.0, 90.0, 100.0};
  string grade[] = {"F", "D", "C" , "B", "A"};
  
  int gradeLevel = 0;
  string studentGrade = "A";
  maxGradeLevel = grade.length()-1;
  
  while( (studentGrade  == "A") && (gradeLevel < maxGradeLevel))
  {
      if( StudentScore < rangeLimit(gradeLevel))
       {
           StudentGrade = grade[gradeLevel];
           break;
       }
       else
        gradeLevel++;
  }

需要注意的一些细节:
1,留心端点。
2,考虑用二分查找取代顺序查找。
3,考虑用索引访问来取代阶梯技术

参考:

  • 代码大全(第二版)

  • https://learning.oreilly.com/library/view/Code+Complete,+Second+Edition/0735619670/ch18s02.html

  • https://blog.csdn.net/weixin_34072458/article/details/88655317

  • https://www.cnblogs.com/youxin/p/3202034.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

表驱动法(Table-Driven Methods) 的相关文章

  • 以OpenGL/ES视角介绍gfx-hal(Vulkan) Shader/Program接口使用

    文档列表见 Rust 移动端跨平台复杂图形渲染项目开发系列总结 目录 背景 The right way to tackle this in Vulkan is to use resource descriptors A descriptor
  • Mysql 数据库

    数据库基础 1 什么是数据库 用来存储数据 数据库可在硬盘及内存中存储数据 数据库与文件存储数据的区别 数据库本质也是通过文件来存储数据 数据库的概念就是系统的管理存储数据的文件 数据库介绍 本质就是存储数据的C S架构的socket套接字
  • python 历险记(五)— python 中的模块

    目录 前言 基础 模块化程序设计 模块化有哪些好处 什么是 python 中的模块 引入模块有几种方式 模块的查找顺序 模块中包含执行语句的情况 用 dir 函数来窥探模块 python 的内置模块有哪些 结语 参考文档 系列文章列表 前言
  • 树06--二叉树中和为某一值的路径

    树06 二叉树中和为某一值的路径 jz24 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 输入一颗二叉树的根节点和一个整数 按字典序打印出二叉树中结点值的和为输入整数的所有路径 路径定义为从树的根结点开始往下一直到叶结点所经
  • 手把手教你实现一个向量

    文章目录 什么是向量 向量提供哪些接口 实现 宏定义 定义类 成员变量 构造函数与析构函数 构造函数 析构函数 成员函数 size get r put r e expand insert r e remove lo hi remove r
  • 字符串09--表示数值的字符串

    字符串09 表示数值的字符串 jz53 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 请实现一个函数用来判断字符串是否表示数值 包括整数和小数 例如 字符串 100 5e2 123 3 1416 和 1E 16 都表示数值
  • 数据结构——计算节点个数和二叉树高度(C语言版)

    摘自 数据结构 计算节点个数和二叉树高度 C语言版 作者 正弦定理 发布时间 2020 12 12 23 27 09 网址 https blog csdn net chinesekobe article details 111086664
  • 算法学习——贪心算法之币种统计

    算法描述 币种统计 单位给每一位员工发工资 精确到元 为了保证不临时换零钱 使得每个员工取款的张数最少 在取工资前统计所有员工所需要的各种票面的张数 约定票种为100 50 20 10 5 2 1元 并验证币种统计是否正确 算法思路 算法描
  • 数理统计知识整理——回归分析与方差分析

    题记 时值我的北科研究生第一年下 选学 统计优化 课程 备考促学 成此笔记 以谨记 1 线性回归 1 1 原理分析 要研究最大积雪深度x与灌溉面积y之间的关系 测试得到近10年的数据如下表 使用线性回归的方法可以估计x与y之间的线性关系 线
  • 区块链中的哈希算法

    区块链中的密码学 密码学在区块链中的应用主要有两个 哈希算法与非对称加密算法 这次主要对哈希算法进行详细的说明 哈希算法 哈希算法的特点有 1 输入可以为任意大小的字符串 2 产生固定大小的输出 3 可以在合理的时间内算出输出值 若要满足密
  • 【试题】排列组合

    在写一个远程的代码 如果本地有M个显示器 远程有N个显示器 M lt N 依据分辨率 显示器刷新频率等要求 需要对远程的N个显示器进行最佳分辨率修改 之后 需要从N个远程显示器中选择M个 跟本地显示器进行一对一的匹配 即从 A N M N
  • 插入排序超详解释,一看就懂

    目录 一 插入排序的相关概念 1 基本思想 2 基本操作 有序插入 二 插入排序的种类 三 直接插入排序 1 直接插入排序的过程 顺序查找法查找插入位置 2 使用 哨兵 直接插入排序 四 直接插入排序算法描述 五 折半插入排序 1 查找插入
  • 雪糕的最大数量 排序+贪心

    雪糕的最大数量 雪糕的最大数量 题目描述 样例 数据范围 思路 代码 题目描述 夏日炎炎 小男孩 Tony 想买一些雪糕消消暑 商店中新到 n 支雪糕 用长度为 n 的数组 costs 表示雪糕的定价 其中 costs i 表示第 i 支雪
  • 牛客剑指offer刷题其他算法篇

    文章目录 构建乘积数组 题目 思路 代码实现 第一个只出现一次的字符
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • 【数据结构】单链表的定义和操作

    目录 1 单链表的定义 2 单链表的创建和初始化 3 单链表的插入节点操作 4 单链表的删除节点操作 5 单链表的查找节点操作 6 单链表的更新节点操作 7 完整代码 嗨 我是 Filotimo 很高兴与大家相识 希望我的博客能对你有所帮助
  • 按照层次遍历结果打印完全二叉树

    按照层次遍历结果打印完全二叉树 按照推论结果 l 层首个节点位置 2 h l 1 l 层节点间距 2 h l 1 1 编码实现 public static
  • 排序:计数排序

    一 概念 计数排序是非比较排序 是对哈希直接定址法的变形应用 二 思想 利用数组统计相同数据出现的次数 例如整型数据m出现n次 就在数组m位置记录数据为n 最后从头遍历数组打印数据即可 通俗来讲就是 数组下标即为数据 下标所指位置的值即为数
  • 高精度运算合集,加减乘除,快速幂,详细代码,OJ链接

    文章目录 零 前言 一 加法 高精度加法步骤 P1601 A B 二 减法 高精度减法步骤
  • 最大流-Dinic算法,原理详解,四大优化,详细代码

    文章目录 零 前言 一 概念回顾 可略过 1 1流网络 1 2流 1 3最大流 1 4残留网络 1 5增广路

随机推荐

  • 域中DC和AD的区别

    今天朋友问我DC和AD的区别时 我也是一脸懵X 所以我查了一些资料 做个小总结 域 我的理解是他就是一个架构 和工作组类似 和工作组最大的区别就是 工作组没有管理者 而域可以集中管理 再详细一点的解释就是在工作组上你一切的设置比如在本机上进
  • Vue引入并使用Element-UI组件库的两种方式

    前言 在开发的时候 虽然我们可以自己写css或者js甚至一些动画特效 但是也有很多开源的组件库帮我们写好了 我们只需要下载并引入即可 vue和element ui在开发中是比较般配的 也是我们开发中用的很多的 下面就介绍下如何在eue项目中
  • 博图db块变量导出_博途中,DB里定义的变量的改变

    问题描述 1 新的博途中 生成一个全局DB 打开 在第一行自动生成了 名称 为static的变量 名称无法修改 数据类型无法选择 而在老版的STEP7里 分明是一个无名称 数据类型是STRUCT 无法重新选择 的变量 为什么做了这样的改变
  • 理解super().__init__()

    目录 一 写在前面 本文仅为个人的理解 如有错误欢迎指正 二 super init 的含义 三 代码实验 四 理解super init 五 Reference 一 写在前面 本文仅为个人的理解 如有错误欢迎指正 二 super init 的
  • AdaGrad(自适应梯度算法),Adaptive

    学习衰减率 随着学习的进行 使得学习率逐渐减小 AdaGrad会为参数的每个元素适当的体哦阿正学习率 coding utf 8 import numpy as np class AdaGrad def init self learning
  • template模板:泛型化编程

    一 在函数中使用模板 template
  • macbookpro接口叫什么_了解这些常用接口一定会有用的

    日常使用手机 电脑以及其他电子产品 免不了要跟各种接口打交道 周末花了些时间查了些资料 并总结自己的实际使用经验 跟大家聊一聊我们日常使用手机 iPad 电脑 外设中常用到的接口 讲明白各种接口是一件非常复杂的事情 我会尽量只写日常中常见到
  • 【深度学习】AAAI 2024,14000篇投稿,大家都写了啥?

    夕小瑶科技说 原创作者 python 8月16日截稿的AAAI 2024 从投稿ID看 已超14000篇投稿 这么多投稿 大家都写了啥 今年什么话题最火 和往年相比 今年的投稿趋势又有什么变化 本文中 小编通过对比AAAI 2024与202
  • 文本分类(六):使用fastText对文本进行分类--小插曲

    需要注意的问题 1 linux mac 平台 2 标签中的下划线是两个 两个 两个 环境说明 python2 7 linux 自己打自己脸 目前官方的包只能在linux mac环境下使用 误导大家了 对不起 测试facebook开源的基于深
  • React全家桶-react-router原理实现

    29 9React课程 第05节 react全家桶 第5节 react全家桶 第5节 react全家桶 App js exact精确匹配 可以使用switch独占如果有一个匹配不会继续往下走 一般要与exact配合使用 否则下面不会执行 f
  • c++显示实例化和显示具体化

    1 实例化 instantiation 实例化是指编译器使用函数 或者是类 模板为特定类型生成函数 类 定义 编译器不会为函数 或者类 模板生成定义 只有当我们为函数 或者类 模板指定了一个特定类型时 编译器才会生成 编译器为特定类型的函数
  • git克隆项目时用户名密码是什么_git clone github项目的两种方式(http协议和ssh 协议)介绍...

    简介 在使用git来进行版本控制时 为了得一个项目的拷贝 copy 我们需要知道这个项目仓库的地址 Git URL Git能在许多协议下使用 所以Git URL可能以ssh http s git 或是只是以一个用户名 git 会认为这是一个
  • Google 奔跑吧小恐龙

    Google 奔跑吧小恐龙 在Java中 可以使用JavaFX图形框架来实现游戏界面 使用多线程技术来实现游戏循环和动画效果 以下是使用JavaFX和多线程实现奔跑吧小恐龙游戏的代码示例 1 创建游戏面板并初始化游戏元素 public cl
  • python:解决pycharm运行py文件时只有unittest选项的方法

    有时候在编完脚本开始运行时 发现某个py脚本右键运行的选项不是run 二是run in unittest 试过很多方法都不能很好的去除 主要是因为脚本中含有test字符串 一种解决方法是将脚本中所有的函数和类的test字符串改为其他的 但是
  • 二维光子晶体带隙仿真Matlab完全程序_平面波展开法

    本程序为二维光子晶体Matlab仿真程序 该结果与文献 1 Molding the flow of light p68 figure 2相互吻合 主程序 This is a simple demo for Photonic Crystals
  • MinIO

    文章目录 安装 依赖 使用 下载地址 链接 https pan baidu com s 1V qK13gpddcnlq czc v3A 提取码 yyds 安装 docker run d p 9000 9000 p 9001 9001 nam
  • 【MySQL(一)】WAL 机制

    WAL全称是write ahead log 也就是更新数据之前先更新日志 之前不太明白为什么要用这个 也查了很多博客 发现很多都没说到根本原因上 基本的解释都是什么使用redo log恢复数据之类的 其实Mysql使用WAL的原因根本就不是
  • vue 不能监听对象属性的改变

    vue 不能监听对象属性的改变 需要重新赋值后才会渲染页面 div item div 方法 commonClick index this active index this active index
  • post和get的区别

    1 get是从服务器上获取数据 post是向服务器传送数据 2 get是把参数数据队列加到提交表单的ACTION属性所指的URL中 值和表单内各个字段一一对应 在URL中可以看到 post是通过HTTP post机制 将表单内各个字段与其内
  • 表驱动法(Table-Driven Methods)

    背景 表驱动方法是一种方案 它允许您在表中查找信息 而不是使用逻辑语句 if和 case 来查明信息 实际上 您可以使用逻辑语句选择的任何内容 都可以使用表进行选择 在简单情况下 逻辑语句更容易 更直接 随着逻辑链变得越来越复杂 表格变得越