您的位置:首页 > 其它

用数组代替if-else和switch-case语句

2014-01-24 22:10 603 查看
表驱动法(Table-Driven Approach),通过在表中查找信息,来代替很多复杂的if-else或者switch-case逻辑判断。这是一种设计的技巧,可以应用很多的场合,不仅可以提高程序的性能,也能大大减少代码量,使得代码变得高效和优雅。下面将使用一个例子来展示这种方法的优点。

当我们需要写一个函数用来获取指定月份的天数时,我们可能会写出以下的代码段:

//判断是否闰年,若为闰年返回1,否则返回0
int IsLeapYear(unsigned int year)
{
if ((0 == year % 4 && 0 != year % 100) || (0 == year % 400))
return 1;
return 0;
}

//获取year年month月的天数
unsigned int GetMonthDays(unsigned int year, unsigned int month)
{
unsigned int days = 0;
if (1 == month) {days = 31;}
else if (2 == month)
{
if (IsLeapYear(year)) {days = 29;}
else {days = 28;}
}
else if (3 == month) {days = 31;}
else if (4 == month) {days = 30;}
else if (5 == month) {days = 31;}
else if (6 == month) {days = 30;}
else if (7 == month) {days = 31;}
else if (8 == month) {days = 31;}
else if (9 == month) {days = 30;}
else if (10 == month) {days = 31;}
else if (11 == month) {days = 30;}
else if (12 == month) {days = 31;}

return days;
}

上面的代码通过多个if-else语句,来获取当前月份的总天数,代码看起来还算清晰,但是就是感觉有点冗长和重复,另外,需要进行多次比较才能得到具体的天数,月份越后,比较次数就越多。

编译器在实现switch-case的时候,会用到跳表来优化比较的性能,下面将上面代码的if-else语句换为switch-case的实现。

//获取year年month月的天数
unsigned int GetMonthDays(unsigned int year, unsigned int month)
{
int days = 0;
switch(month)
{
case 1: days = 31; break;
case 2:
{
if (IsLeapYear(year)) {days = 29;}
else {days = 28;}
}break;
case 3: days = 31; break;
case 4: days = 30; break;
case 5: days = 31; break;
case 6: days = 30; break;
case 7: days = 31; break;
case 8: days = 31; break;
case 9: days = 30; break;
case 10: days = 31; break;
case 11: days = 30; break;
case 12: days = 31; break;
default: break;
}

return days;
}

对于上面的switch-case实现,先不论效率有多大提升,单纯的看代码,感觉跟if-else没多大区别,代码还是有点冗长和重复,还是不够简洁。若应用于其他场景,随着case分支越来越多,case分支的代码量越来越大的时候,代码就更难维护了。其实可以看到,当分支越来越多的时候,每个case分支的逻辑其实还是一样的,只是其中的数据改变了而已。若在加分支的时候不小心还有可能修改了逻辑的代码,容易导致出错。

此时,通过表驱动法,可以很容易分离变化的数据和不变化的逻辑,代码如下:

//判断是否闰年,若为闰年返回1,否则返回0
int IsLeapYear(unsigned int year)
{
if ((0 == year % 4 && 0 != year % 100) || (0 == year % 400))
return 1;
return 0;
}

static unsigned int monthdays[2][12] =
{
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
}

//获取year年month月的天数
unsigned int GetMonthDays(unsigned int year, unsigned int month)
{
return monthdyas[IsYeapYear(year)][month - 1];
}

这次代码够整洁了,不仅代码量变少了,而且通过数组地址偏移操作就可以快速得到数据,不需要一大段的比较逻辑,更加高效了。但是这种表驱动法也不是所有场合都能直接用到的,如果要判断的数据不是连续的,如1、5、16、222,就需要做另外的转换,譬如用一个map<int, int>来将原数据转为一堆连续的数字,这样就又可以用到表驱动法了。另外,也可以使用其他更加高级的数据结构来实现,不需要局限于数组,关键都是使用空间来换取时间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐