您现在的位置是:首页 >

成法怎么算详细过程 表驱动法详细资料大全

火烧 2023-04-11 22:35:20 1063
表驱动法详细资料大全 表驱动法,又称之为表驱动、表驱动方法。 “表”是几乎所有数据结构课本都要讨论的非常有用的数据结构。表驱动方法出于特定的目的来使用表,程式设计师们经常谈到“表驱动”方法,但是课本中

表驱动法详细资料大全  

成法怎么算详细过程 表驱动法详细资料大全

表驱动法,又称之为表驱动、表驱动方法。 “表”是几乎所有数据结构课本都要讨论的非常有用的数据结构。表驱动方法出于特定的目的来使用表,程式设计师们经常谈到“表驱动”方法,但是课本中却从未提到过什么是"表驱动"方法。表驱动方法是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if或Case)来把它们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况下,逻辑语句往往更简单而且更直接。但随着逻辑链的复杂,表就变得越来越富有吸引力了。

基本介绍

中文名:表驱动法又称:表驱动、表驱动方法释义:在表中查找信息目的:出于特定的目的 基本内容,数据用法,函式用法,总结,其它参考,什么是表驱动法,简单示例,直接查询,索引查找,分段查找,

基本内容

表驱动法,又称之为表驱动、表驱动方法。 “表”是几乎所有数据结构课本都要讨论的非常有用的数据结构。表驱动方法出于特定的目的来使用表,程式设计师们经常谈到“表驱动”方法,但是课本中却从未提到过什么是"表驱动"方法。表驱动方法是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if或Case)来把它们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况下,逻辑语句往往更简单而且更直接。但随着逻辑链的复杂,表就变得越来越富有吸引力了,通过下面的这个例子大家就能知道什么是所谓的表驱动方法了。

数据用法

假设你需要一个可以返回每个月中天数的函式(为简单起见不考虑闰年), 一个比较笨的方法是一个大的if语句: int iGetMonthDays(int iMonth) { int iDays; if(1 == iMonth) {iDays = 31;} else if(2 == iMonth) {iDays = 28;} else if(3 == iMonth) {iDays = 31;} else if(4 == iMonth) {iDays = 30;} else if(5 == iMonth) {iDays = 31;} else if(6 == iMonth) {iDays = 30;} else if(7 == iMonth) {iDays = 31;} else if(8 == iMonth) {iDays = 31;} else if(9 == iMonth) {iDays = 30;} else if(10 == iMonth) {iDays = 31;} else if(11 == iMonth) {iDays = 30;} else if(12 == iMonth) {iDays = 31;} return iDays; } 可以看出本来应该很简单的一件事情,代码却是这么冗余,解决这个的办法就可以用表驱动方法。 static int aiMonthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 我们可以先定义一个静态数组,这个数组用来保存一年十二个月的天数 int iGetMonthDays(int iMonth) { return aiMonthDays[(iMonth - 1)]; } 接下来不用多说了,大家都能看出用这种表驱动的方法代替这种情逻辑性不强,但分支很多的代码是多么令人"赏心悦目"的了。

函式用法

函式指针在表驱动方法中的套用 在使用表驱动方法时需要说明的一个问题是,你将在表中存储些什么。 在某些情况下,表查寻的结果是数据。如果是这种情况,你可以把数据存储在表中。 在其它情况下,表查寻的结果是动作。在这种情况下,你可以把描述这一动作的代码存储在表中。 在某些语言中,也可以把实现这一动作的子程式的调用存储在表中,也就是将函式的指针保存在表中,当查找到这项时,让程式用这个函式指针来调用相应的程式代码,这个就是函式指针在表驱动方法中的套用。 其实说到这已经说了很多表驱动方法的相关问题了,现在要把函式指针也套用进去,很多人应该已经想到会是个什么样子了,其实也很简单,通过下面这两段伪代码的例子就可以充分体现函式指针在表驱动方法中套用会使代码更加精致。 我们在写一段程式的过程中会经常遇到这样的问题,我们在写一个Task的主函式中有时会要等待不同的Event通知,并且处理不同的分支,首先有如下的Event Bit的宏定义和相应的处理函式的声明。 #define TASK_EVENT_BIT00 (1 << 0) #define TASK_EVENT_BIT01 (1 << 1) #define TASK_EVENT_BIT02 (1 << 2) #define TASK_EVENT_BIT03 (1 << 3) #define TASK_EVENT_BIT04 (1 << 4) #define TASK_EVENT_BIT05 (1 << 5) #define TASK_EVENT_BIT06 (1 << 6) #define TASK_EVENT_BIT07 (1 << 7) #define TASK_EVENT_BIT08 (1 << 8) #define TASK_EVENT_BIT09 (1 << 9) void vDoWithEvent00(); void vDoWithEvent01(); void vDoWithEvent02(); void vDoWithEvent03(); void vDoWithEvent04(); void vDoWithEvent05(); void vDoWithEvent06(); void vDoWithEvent07(); void vDoWithEvent08(); void vDoWithEvent09(); 我们一般首先想到的写法是 unsigned long ulEventBit; for(;;) { xos_waitFlag(&ulEventBit); if(ulEventBit & TASK_EVENT_BIT00) { vDoWithEvent00(); } if(ulEventBit & TASK_EVENT_BIT01) { vDoWithEvent01(); } if(ulEventBit & TASK_EVENT_BIT02) { vDoWithEvent02(); } if(ulEventBit & TASK_EVENT_BIT03) { vDoWithEvent03(); } if(ulEventBit & TASK_EVENT_BIT04) { vDoWithEvent04(); } if(ulEventBit & TASK_EVENT_BIT05) { vDoWithEvent05(); } if(ulEventBit & TASK_EVENT_BIT06) { vDoWithEvent06(); } if(ulEventBit & TASK_EVENT_BIT07) { vDoWithEvent07(); } if(ulEventBit & TASK_EVENT_BIT08) { vDoWithEvent08(); } if(ulEventBit & TASK_EVENT_BIT09) { vDoWithEvent09(); } } 可以看出这样写是不是显得程式太长了呢。 下面我们再看看同样的一段代码用函式指针和表驱动方法结合的方法写出会是什么样子。 typedef struct { unsigned long ulEventBit; void (*Func)(void); } EventDoWithTable_t; static const EventDoWithTable_t astDoWithTable[] = { { TASK_EVENT_BIT00 , vDoWithEvent00}, { TASK_EVENT_BIT01 , vDoWithEvent01}, { TASK_EVENT_BIT02 , vDoWithEvent02}, { TASK_EVENT_BIT03 , vDoWithEvent03}, { TASK_EVENT_BIT04 , vDoWithEvent04}, { TASK_EVENT_BIT05 , vDoWithEvent05}, { TASK_EVENT_BIT06 , vDoWithEvent06}, { TASK_EVENT_BIT07 , vDoWithEvent07}, { TASK_EVENT_BIT08 , vDoWithEvent08}, { TASK_EVENT_BIT09 , vDoWithEvent09} }; ulong ulEventBit; int i; for(;;) { xos_waitFlag(&ulEventBit); for(i = 0 ; i < sizeof(astDoWithTable)/sizeof(astDoWithTable); i ++) { if ( ( ulEventBit & astDoWithTable[i].ulEventBit ) && ( astDoWithTable[i].Func != NULL ) ) { (*astDoWithTable[i].Func)(); } } } 可以看出这种代码的风格使代码变得精致得多了,并且使程式的灵活性大大加强了,如果我们还要再加入EventBit,只修改表中的内容就可以了。

总结

通过上面介绍的,相信大家已经对函式指针的使用方法有所了解了,但是需要提醒大家,凡事都要具体情况具体分析,使用函式指针的时候一定要多加小心,因为函式指针有它的一个致命的缺点。 函式指针的致命缺点是:无法对参数 (parameter) 和返回值 (return value) 的类型进行检查,因为函式已经退化成指针,指针是不带有这些类型信息的。少了类型检查,当参数或者反回值不一致时,会造成严重的错误。有些编译器并不会帮我们找出函式指针这样的致命错误。所以,许多新的程式语言都不支持函式指针了,而改用其他方式。 从上面的例3中我们可以看到 int max(int x,int y){ return x>y?x:y; } int min(int x,int y){ return x<y?x:y; } int add(int x,int y){ return x+y; } 这三个函式都有两个参数,而在后面却把处理函式定义成 int process(int x,int y, int (*f)()) { return (*f)(x,y); } 其中第三个参数是一个函式的指针,从表面上看它是个没有参数,并且返回int型的函式的指针,但是在后面却用process(a,b,max)的方式进行调用,max带有两个参数,这段程式在C语言中就可以顺利的编译通过(但是在C++中却编译不通过),可以看出如果编译器没有检查出错误,而我们又不小心写错的话,后果是很严重的,比如return (*f)(x,y);不小心写成return (*f)(x);在C语言中可以正常的被编译通过,但是运行结果一定不是我们想要的。 因此在C语言中使用函式指针的时候,一定要小心“类型陷阱”,小心地使用函式指针,只有这样我们才可以从函式指针中获益。

其它参考

什么是表驱动法

所谓表驱动法(Table-Driven Approach),简单讲是指用查表的方法获取值。 我们平时查字典以及念国中时查《数学用表》找立方根就是典型的表驱动法。在数值不多的时候我们可以用逻辑语句(if 或case)的方法来获取值,但随着数值的增多逻辑语句就会越来越长,此时表驱动法的优势就显现出来了。

简单示例

在我几天前的一篇条码序列的文章中提到用36进制(A表示10,B表示11,...)来表示更大的数字,如果用逻辑来表示的话可能会写成: if(i<10) { numChar=Convert.ToChar(i); } else if (i==10) { numChar=&apos;A&apos; } else if (i==11) { numChar=&apos;B&apos; } else if (i==11) { numChar=&apos;C&apos; } . else if (i==36) { numChar=&apos;Z&apos; } 代码实在是太长了,按时髦的说法“代码臭味”太浓了。 但要是存在一个表的话,代码就非常简单了 C# code 使用表驱动法 numChar=numChars[i]; 这行代码假设已经建好了一个numChars的表,此时我们将数据存在一个表中而不是if判断中. 三:查表的方式 在使用表驱动法的时候必须要解决的一个问题就是如何查表. 我们可以用非常直接的方式查一个表,就如前面示例讲的我就用数组下标就好了,但你发现有谁查字典甚至《数学用表》是直接依靠页码来查的吗?这是肯定行不通的。 常用的查表方式有

直接查询

直接查询,是指无需绕圈子,用下标的方式就能顺利的获取到数据; if(day==1) { dayName="星期一"; } else if(day==2) { dayName="星期二"; } else if(day==0) { dayName="星期日"; } 实现同样的功能,我们可以将这些数据存储到一个表里 C#代码 表驱动法获取星期名称 string[] dayNames=new string[]{"星期日","星期一","星期二","星期三","星期四","星期五","星期六"}; dayName=dayNames[day]; 只要一条语句就可以代替长长的if-else语句 如果某一天我们的网站要根据访客选择的语言来显示星期几的话 表驱动法仍然很简单 C#代码 表驱动法获取星期名称 dayName=dayNames[day,(int)GetUserLanguage()]; 但如果是用if-else的话,那长度可就的翻番啊。

索引查找

在用一个简单方法无法将“英文单词”这样数据转换成表下标时,可以考虑使用索引来查找.在中的Dictionary 就是一个典型的例子 C#代码 获取一个用户对象 Dictionary users=GetAllUsers(); User tom=users["Tom"]; 其实我们常用的DataTable就可以用索引查找的方式来获取数据 假如有个人员信息的table C#代码 用索引查找方式从DataTable中获取第一个用户的姓名 DataTable userInfo=dal.GetAllUsersInfo(); name=userInfo.Rows.Columns["UserName"]; 使用索引查询的主要优点就是代码的可读性大为增强,可维护性也更好 C#代码 用直接查找方式从DataTable中获取第一个用户的姓名 DataTable userInfo=dal.GetAllUsersInfo(); name=userInfo.Rows[i].Columns; 对比上一段代码,columns很让人不知所谓;此外如果返回的Datable返回的列顺序改变的话就必须更改魔术数字3,否则代码就会出错;

分段查找

分段查找通过确定数据所处的范围确定分类(下标) 使用分段查找,需要先把每一个区间的上限写在一个表中,然后通过循环确定所处的区段,最后获得相应的等级 C#示例 根据分数查绩效等级 private static double[] rangeLimit = { 60.0, 75.0, 85.0, 95.0,100.0 }; private static string[] grade = {"不合格", "合乎要求", "良好", "优秀" ,"卓越"}; private static readonly int maxLevel = grade.Length - 1; public static string CalculateGrade(double score) { int level = 0; while (level <= maxLevel) { if (score < rangeLimit[level]) { return grade[level]; } else { level++; return grade[maxLevel]; }  
永远跟党走
  • 如果你觉得本站很棒,可以通过扫码支付打赏哦!

    • 微信收款码
    • 支付宝收款码