use*_*336 15 algorithm optimization
我有一段代码,我想优化它的可读性和性能以及酷感.现在我有这个丑陋的东西:
if ( cond1 && cond2 && cond3 && !cond4)
{
// do something
}
else if ( cond1 && cond2 && !cond3 && cond4)
{
// do something
}
else if ( cond1 && !cond2 && cond3 && cond4)
{
// do something
}
else if (!cond1 && cond2 && cond3 && cond4)
{
// do something
}
else
{
// do something
}
Run Code Online (Sandbox Code Playgroud)
其中cond1
,cond2
,cond3
和cond4
是已被上面的代码块之前初始化布尔值.我想让它更快,更简单,更酷.
我正在考虑这样做:
int val = (cond1 ? 0 : 1) + 2 * (cond2 ? 0 : 1) + 4 * (cond3 ? 0 : 1) + 8 * (cond4 ? 0 : 1);
if (val == 8)
{
// do something
}
else if (val == 4)
{
// do something
}
else if (val == 2)
{
// do something
}
else if (val == 1)
{
// do something
}
else
{
// do something
}
Run Code Online (Sandbox Code Playgroud)
这有用还是有缺陷?有没有更好的办法?在查看多个条件的不同组合时,获得所需结果的典型方法是什么?
Apr*_*ori 25
您希望将这些值转换为位标志.也就是说,对于每个条件,您都希望在整数类型中设置或不设置.然后,您的案例中的每个4位值代表您的上述ANDed条件之一.之后,您可以使用switch语句.它可以说更具可读性,编译器通常可以将其优化为跳转表.也就是说,它只是将您的程序计数器偏移到查找表中的某个值或某种类型的值,并且您不再需要检查每个值的组合.通过这种方式,对ANDed情况的检查变为恒定时间而不是线性,即如果你添加了4个标志,现在有256个组合而不是16个,那么这种方法在大方式上同样快.或者,如果您不信任编译器使switch语句成为跳转表,则可以使用该flags
值作为函数指针数组的索引来自行完成.值得注意的是ORed枚举案例值在编译时被折叠或预先计算.
enum {
C1 = 0x1,
C2 = 0x2,
C3 = 0x4,
C4 = 0x8
};
unsigned flags = 0;
flags |= cond1 ? C1 : 0x0;
flags |= cond2 ? C2 : 0x0;
flags |= cond3 ? C3 : 0x0;
flags |= cond4 ? C4 : 0x0;
switch (flags) {
case 0: // !cond1 && !cond2 && !cond3 && !cond4
// do something
break;
case C1: // cond1 && !cond2 && !cond3 && !cond4
// do something
break;
case C2: // !cond1 && cond2 && !cond3 && !cond4
// do something
break;
case C1 | C2: // cond1 && cond2 && !cond3 && !cond4
// do something
break;
case C3: // !cond1 && !cond2 && cond3 && !cond4
// do something
break;
case C1 | C3: // cond1 && !cond2 && cond3 && !cond4
// do something
break;
case C2 | C3: // !cond1 && cond2 && cond3 && !cond4
// do something
break;
case C1 | C2 | C3: // cond1 && cond2 && cond3 && !cond4
// do something
break;
case C4: // !cond1 && !cond2 && !cond3 && cond4
// do something
break;
case C1 | C4: // cond1 && !cond2 && !cond3 && cond4
// do something
break;
case C2 | C4: // !cond1 && cond2 && !cond3 && cond4
// do something
break;
case C1 | C2 | C4: // cond1 && cond2 && !cond3 && cond4
// do something
break;
case C3 | C4: // !cond1 && !cond2 && cond3 && cond4
// do something
break;
case C1 | C3 | C4: // cond1 && !cond2 && cond3 && cond4
// do something
break;
case C2 | C3 | C4: // !cond1 && cond2 && cond3 && cond4
// do something
break;
case C1 | C2 | C3 | C4: // cond1 && cond2 && cond3 && cond4
; // do something
};
Run Code Online (Sandbox Code Playgroud)
此外,这涵盖了所有组合.如果您只是需要一些子集随时删除一些案例.编译器非常擅长优化switch语句.它可能比你可以自己动手的任何聪明的特殊情况算术技巧更快.
enum {
C1 = 0x1,
C2 = 0x2,
C3 = 0x4,
C4 = 0x8
};
unsigned flags = 0;
flags |= cond1 ? C1 : 0x0;
flags |= cond2 ? C2 : 0x0;
flags |= cond3 ? C3 : 0x0;
flags |= cond4 ? C4 : 0x0;
switch (flags) {
case C1 | C2 | C3: // cond1 && cond2 && cond3 && !cond4
// do something
break;
case C1 | C2 | C4: // cond1 && cond2 && !cond3 && cond4
// do something
break;
case C1 | C3 | C4: // cond1 && !cond2 && cond3 && cond4
// do something
break;
case C2 | C3 | C4: // !cond1 && cond2 && cond3 && cond4
// do something
break;
default:
// do something
;
};
Run Code Online (Sandbox Code Playgroud)
Sne*_*tel 16
好吧,最愉快的写作方式可能就是这样
if(cond1 + cond2 + cond3 + cond4 == 3)
{
if(!cond1)
{
// do something
}
else if(!cond2)
{
// do something
}
else if(!cond3)
{
// do something
}
else // !cond4
{
// do something
}
}
else
{
// do something
}
Run Code Online (Sandbox Code Playgroud)
不过,我对那些不在数组中的值很谨慎.
根据我的经验 - 有一系列长if/else语句表示类似但可区分的行为.
我通常尝试引入一个接口并实现捕获此行为的类,并调用将产生所需结果的方法.
这使得代码更具可读性 - 无需重复复杂的流程(可能会在以后嵌套).每个类负责抽象方法的实现,并且操作的对象将具有静态类型的接口,以及其动态类型 - 最匹配的实现类.