我正在使用一些需要大(常量)位数组的代码。由于它包含大的常量跨度(全0或全1),我将其分解为两级表,允许重复跨度(常量或其他),如:
bitn = table2[table1[n/256]+n%256/8]&1<<n%8
此时,table1
的条目都是32(256位)的倍数,但我想知道通过允许table2
中的跨度重叠可以实现显着的节省。所以我的问题是(以摘要形式陈述):
给定长度为K的N个字符串{S_n:n = 1..N},是否有一种有效的方法来找到最短长度的字符串S,使得每个S_n是S的子字符串?
(注意,因为我可能想让我的位数组保持8位对齐,我对该问题的特定应用可能会处理8位字节的字符串而不是字符串的字符串,但问题在任何问题上都有意义字符感 - 位,字节或其他。)
答案 0 :(得分:1)
首先,这个问题可以表述为TSP。我们有一组节点(每个字符串都是一个节点),我们需要找到访问所有节点的路径。字符串x和y之间的距离定义为len(xy)+ len(y),其中xy是具有x和y的最佳字符串,并且以x开头(例如,x = 000111,y = 011100,xy = 0001100 ,距离(x,y)= 8-6 = 2)。
注意,这也服从三角不等式(距离(x,z)&lt; =距离(x,y)+距离(y,z))。距离是从1到k的整数。此外,距离是不对称的。
此版本的TSP称为(1,B)-ATSP。有关此类问题和近似解决方案的分析,请参阅http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.20.3439。
答案 1 :(得分:1)
与具有大部分常量的大型常量位数组有关,这里是设计表的另一种方法供您考虑(我不知道您的确切需求,所以我不能说它是否会有所帮助或不是)。
考虑类似radix tree的内容。为了便于解释,让我定义get函数:
#define TYP_CONST
#define TYP_ARRAY
struct node {
unsigned min;
unsigned max;
int typ;
union {
char *bits;
int constant;
} d;
struct node *left;
struct node *right;
}
struct bit_array {
unsigned length;
struct node *root;
}
int get(struct bit_array *b, unsigned ix)
{
struct node *n = b->root;
if (ix >= b->length)
return -1;
while (n) {
if (ix > n->max) {
n = n->right;
continue;
} else if (ix < n->min) {
n = n->left;
continue;
}
if (n->typ == TYP_CONST)
return n->d.constant;
ix -= n->min;
return !!(n->d.bits[ix/8] & (1 << ix%8));
}
return -1;
}
从人类的角度来说,你想在树上寻找你的位。每个节点都负责一系列位,您可以通过范围进行二进制搜索,以找到所需的范围。
找到范围后,有两个选项:常量或数组。如果不变,只需返回常量(为您节省大量内存)。如果是数组,则在位数组中进行数组查找。
你将有O(log n)查询时间而不是O(1)....虽然它应该仍然非常快。
这里的困难在于设置适当的数据结构很烦人且容易出错。但是你说阵列是不变的,所以这可能不是问题。