表驱动法: 一种编程模式,从表里面查找信息而不使用逻辑语句(if、case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用简单的逻辑语句更为容易和直白,但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。
表驱动法使用总则
使用复杂的逻辑对字符进行分类:
if (( 'a' <= InputChar ) and ( InputChar <= 'z' )) or (( 'A' <= InputChar ) and( InputChar <= 'Z' ))
{
CharType := Letter
}else if ( InputChar = '' ) or ( InputChar = ',' ) or ( InputChar = '.' ) or ( InputChar = '!' ) or ( InputChar = '(' ) or ( InputChar = ')' ) or ( InputChar = ':' ) or ( InputChar = ';' ) or ( InputChar = '?') or ( InputChar = '-' )
{
CharType := Punctuation
}
else if( '0' <= InputChar and InputChar <= '9' )
{
CharType := Digit
}
使用查询表,就可以把每个字符的类型保存在一个用字符编码访问的数组里,那么上述的复杂代码片段就可以替换为:
CharType := CharTypeTable[InputChar];
使用表驱动法的两个问题:
1、怎样从表中查询条目的问题:直接访问、索引访问、阶梯访问
2、在表里面存些什么:数据、动作(函数指针)
直接访问表
直接通过访问数组下标的方式,直接在表里面获取所要的信息数据:
例1: 一个月中的天数
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //直接输入具体的某一月,然后获取到当前月份的天数
如果需要多种条件组合查找,则可以建立多维数组,还需要找一种把数据存放进去的方法,可以使用赋值语句、从磁盘文件中读入数据、计算出这些数据、或者执行任何合适的操作。
例2: 要编写一个打印存储在某一文件中信息的子程序。文件中通常含有 500 条信息,信息共有大约 20 种,每种信息的存储的格式不同。
方法一,基于逻辑的方法:在以逻辑为基础的方法中,信息读取子程序要用一个循环来读取每条信息,再根据信息识别标志判别出它的种类,然后再从 20 个打印子程序中调用相应的子程序来打印它。
方法二,表驱动法:信息读取子程序首先利用循环来读取每条信息的开头,再利用识别标志判定它的种类,然后在 Message 数组中查寻关于该信息的描述(每个成员的类型),然后调用同一个(而不是 20 个中的某一个)子程序来解释和打印信息。
While more fields to print
Get the field type from the message description
Depending on the type of the field
case of floating point =>
read a floating-point value
print the field label
print the floating-point value
case of integer =>
read a Integer value
print the field label
print the integer value
case of character string =>
read a character string
print the field label
print the character string
构造查询键值:
(1)复制信息从而能够直接使用键值:age1-17的value值相同,但是仍然创建17个数组成员。
(2)转换键值以使其能够直接使用:age1-17的value值相同仍统一使用键值17,大于66统一使用键值66。
(3)把键值转换提取成独立的子程序:例如红黑树,使用键值来查找value值。
索引访问表
索引访问技术的两个主要优点:
1、如果主查询表中的每一条记录都很大,那么创建一个浪费了很多空间的索引数组所用的空间,就要比创建一个浪费了很多空间主查询表的空间小很多。(例:100中商品编号在0-9999之间,存储的信息占100字节,使用索引总共只需要消耗30000字节,不使用索引,需要消耗1000000字节)
2、操作位于索引中的记录有时要比操作位于主表中的记录更方便更廉价。
3、可以使用类似于红黑树的形式,组成子程序,使用索引直接找到,存放信息的地址。
阶梯访问表
例:≥90% A < 90.0% B < 77.5% C < 65.0% D < 50.0% F对于不同的范围对应不同的等级
Dim rangeLimit() As Double = {50.0, 65.0, 75.0, 90.0, 100.0}
Dim grade() As String={"F", "D", "C", "B", "A"}
maxGradeLevel = grade.Length - 1
assign a grad to a student based on the student's score
GradeLevel= 1
StudentGrade = ”A"
while( StudentGrade = "A" and GradeLevel < MaxGradeLevel )
if( StudentScore < RangeLimit( GradeLevel ) ) then
StudentGrade = Grade ( GradeLevel)
end if
GradeLevel = GradeLevel + 1
Wend
在使用阶梯技术的时候需要注意的一些细节:
1、留心端点,注意<和<=
2、考虑用二分查找取代顺序查找,如果列表很大的话,从头查找是很耗费性能的
3、考虑使用索引访问来取代阶梯技术
小节
1、考虑把表驱动法作为复杂逻辑的替换方案。
2、使用表的关键决策是决定如何去访问表:直接访问,索引访问、阶梯访问。
3、使用表的另一项关键决策是决定应该把什么内容放入表中。
4、需要保存浮点数和范围数时,使用阶梯访问的形式。