if-else或switch-case的最快替代品

时间:2013-09-05 18:19:04

标签: c algorithm

我有以下定义:

typedef enum
{
    def   = 0,
    m1    = 1,
    m2    = 2,
    m3    = 4,
    m4    = 6,
    m5    = 17,
    m6    = 33,
    m7    = 41,
    m8    = 47,
    m9    = 50,
    m10   = 51,
    m11   = 58,
    m12   = 89,
    m13   = 132,
    m14   = 135
} my_enums;

我正在寻找一种最快的方法来检查函数的参数是否属于其中一个值m1..m14。显而易见的实现是if(p == m1 || p == m2 ...)或switch-case alternative。

有更快的东西吗? m1~m14的值是固定的,不能在连续的范围内。

感谢。

7 个答案:

答案 0 :(得分:6)

我能想到的最快的是从0到135的字节数组。如果该项是您的有效枚举之一,则将值设置为1,如果不是,则将值设置为0。然后你可以写:

if (valuesArray[x])
    YahooItsGood();

当然,如果您的范围很大,那么这不起作用。

如果传入的值可能超出该范围,那么您需要更多逻辑:

if (x >= 0 && x < 136 && valuesArray[x])
    YahooItsGood();

当然,每个项目实际上只需要一个位,所以你可以使用一个1/8大小的数组来节省大量内存。测试值的逻辑变得更加复杂,但它仍然比一系列if / else或二进制搜索更快。

如果你有一个更大的集合,那么你可能想要构建一个哈希表。它不会像直接查找那么快,但是当值范围大得多时,它会使用更少的内存。

答案 1 :(得分:6)

switch语句是更好的选择。它有助于了解编译器可以使用的技巧使switch语句非常优化(在大多数情况下)。很多时候,比你自己想出的更好。

如果值不连续,则编译器可以求助于具有O(log(n))性能的静态二进制决策树。对于连续值列表,它将构造一个跳转表,即O(1)。相比之下,if-else结构是O(n)。

我建议你在使用其他方法之前完全理解你可以从switch语句中得到什么。

答案 2 :(得分:1)

一个简单的想法,如果你可以保证输入是8位宽:创建一个大小为256的静态int数组,在你的枚举指定的索引处为1,在其他地方为0。然后你要做的就是一次数组查找。

答案 3 :(得分:0)

if(p/7==0 && (p%6!=3 ||p%6!=5))
 // p is present, p = 0,1,2,4,6
if(p==17||p==33.....remaining 7 numbers)
//p is present

所以你把它们从14个条件评估减少到12个...... 也许试着像我上面那样在价值观中找到一些关系。

答案 4 :(得分:0)

由于您需要最快的一个,因此位操作应该比字节快。

你可以有17个八位字节。对于每个位,如果该位是您想要的,则将其标记为1,否则为0.对于每次查找,只需计算Octet id和要检查的位,然后检查它并获得结果。

答案 5 :(得分:0)

我更喜欢二分搜索,因为值是有序的。

一个定义一个数组:

  my_enums enumv[17] = {def, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, -1, -1};

(最后2个值是中心,它们对结果没有影响)。

然后进行二元搜索:

  int s = 0;
  for (int i = 8; i; i /= 2)
        if (p >= enumv[s+i])
           s += i;
  if ( p >= 0 && p == enumv[s])
     printf("Happy\n");
  else
     printf("Unhappy\n");

如果您不想要所有“for”的东西,并且由于您只有15个值,这个算法可以展开并“手头”编写,以便更快:

  int s = 0;
  s += 8*(p >= enumv[s+8]); 
  s += 4*(p >= enumv[s+4]);
  s += 2*(p >= enumv[s+2]);
  s +=   (p >= enumv[s+1]);

  if (p >= 0 && p == enumv[s])
     printf("Happy\n");
  else
     printf("Unhappy\n");

答案 6 :(得分:0)

我的2美分 - 在MSB上使用按位运算进行分而治之。看到32在这里接近中位数,首先将表格分成两半

    if (p & 32)

下一级将错误情况与(p&amp; 4)进行比较,将真实情况与(p&amp; 64)进行比较 - 这使得每个分支中只有3个选项(可以由逻辑或者覆盖) ,除了32和64之间的一个,可以使用(p&amp; 48)进一步细分(这个不是2的圆幂,所以它只适用于某些情况,我想只有MSB相等)

这里的好处是你已经完成了二进制搜索(即使在你的数字是连续的最坏情况下,你在整个区域进行二进制搜索,仍然是log(MAX_N)),你正在做所以使用编译器可以预测的廉价按位运算(或者你可以继续自己做)