考虑类似C语言的典型枚举类型:
enum foo {
FOO_A,
FOO_B,
FOO_C,
/* ... */
FOO_N
};
对enum foo
类型的值有switch语句,可能无法处理某些枚举值:
enum foo bar;
/* ... */
switch (bar) {
case FOO_A: /* ... */
case FOO_B: /* ... */
case FOO_D: /* ... */
case FOO_L: /* ... */
default: /* ... */
}
现在,为了处理足够多的枚举值,编译器将使用大小为的跳转表来实现switch语句(<最高处理值> - <最低处理值> + 1)*的sizeof(无效*)的
考虑我有多个这样的switch语句已知使用跳转表,因为每个语句都知道正在处理哪些值而哪些值不是。如何以某种方式对enum foo
中的值重新排序,生成的所有跳转表的总大小是最小的?
这是一个略微简化的示例,假设编译器为所有switch语句生成跳转表。这是枚举:
enum example {
EX_A,
EX_B,
EX_C,
EX_D
};
这是两个开关语句:
enum example a, b;
switch (a) {
case EX_A: /* ... */
case EX_C: /* ... */
default: /* ... */
}
switch (b) {
case EX_B: /* ... */
case EX_D: /* ... */
default: /* ... */
}
对于此示例,编译器将生成两个跳转表,每个跳转表包含三个条目(在第一种情况下从EX_A
到EX_C
,在第二种情况下从EX_B
到{{1用于跳转表的总共6个机器字。如果我像这样重新排序枚举:
EX_D
我只需要4个数据字作为跳转表。
答案 0 :(得分:4)
这个问题是NP难的,因为它概括了从图到超图的最小线性排列问题(MinLA),MinLA是NP-hard(Garey-Johnson-Stockmeyer 1976)。
已经完成了一些关于解决MinLA问题的研究。有一个看起来很普遍的Theta(2 ^ n m)时间动态程序(Koren - Harel 2002)。线性编程松弛有很多工作,既可以获得保证的近似值,也可以用于分支定界。不幸的是,这些放松似乎都太大了,无法通过求解器直接消费。可能有人尝试过限制编程,但我的粗略搜索没有任何结果。有许多启发式方法,包括Juvan和Mohar(1992)提出的以下可爱想法:根据拉普拉斯算子的第二个特征向量对标签进行排序。
只有50个标签,如果找到一个可证明的最佳安排,我不会感到惊讶,但如果它没有在实例上进行几轮新颖的算法设计,实现和实验,我会感到惊讶(s ) 出于兴趣。如果你想学习一些涉及的技巧,我会推荐Pascal van Hentenryck在Coursera上的Discrete Optimization课程(我从他加入布朗大学时的早期版本开始)。
答案 1 :(得分:-1)
一种解决方案(可能更快)。是通过做部分蛮力。
如果将每个开关视为一组,则可以首先聚集所有组(即开关)的交集。
拥有以下枚举:
enum example {
EX_A,
EX_B,
EX_C,
EX_D,
EX_E
};
这两个转换语句:
枚举示例a,b;
switch (a) {
case EX_A: /* ... */
case EX_C: /* ... */
case EX_E: /* ... */
default: /* ... */
}
switch (b) {
case EX_B: /* ... */
case EX_D: /* ... */
case EX_E: /* ... */
default: /* ... */
}
交叉点是:
{ EX_E }
其余的元素是:
{ EX_A, EX_B, EX_C, EX_D }
因此,您可以先放置交集,然后浏览其余的所有排列并生成所有跳转表,并查看哪一个是较小的跳转表。这是n! (在这个例子中,您必须查看4!= 24个配置)。