我的结构有3个标识符字段和一个值字段。我有一个这些对象的列表。举一个类比,标识符字段就像是对象的主键。这3个字段唯一标识一个对象。
Class
{
int a1;
int a2;
int a3;
int value;
};
我将拥有此数据类型的1000个对象的列表。我需要通过将a1,a2和a3的值传递给查找函数来检查这些标识键值的特定值,该函数将检查是否存在具有特定值a1,a2和a3的任何对象并返回该值。实现此目标以实现最佳查找时间的最有效方法是什么?
我能想到的一个解决方案是使用长度为1000的3维矩阵并填充其中的值。其查找时间为O(1)。但缺点是。 我需要知道阵列的长度。 2.对于更高的身份字段(比如20),那么我将需要一个20维矩阵,这对于内存来说是一种过度杀伤力。对于我的实际实现,我有23个标识字段。
您能否建议一种存储这些数据的好方法,这样可以获得最佳的查找时间?
答案 0 :(得分:4)
创建一个包含所有标识字段的密钥类,并定义适当的equals函数和散列方法,然后使用散列映射从密钥类映射到其关联值。在预期的情况下,这将为您提供每次查找O(1)的时间复杂度,并且它只需要与观察到的实际键组合的数量成比例的空间(通常是数字的两倍,尽管您可以调整时间/空间的常量你想要的权衡,而不是与所有可能的密钥组合成比例的空间。
答案 1 :(得分:0)
使用哈希表(map)。构造密钥为“a1-a2-a3”,并将数据存储到H(密钥)=数据。
答案 2 :(得分:0)
我只需按键对数组进行排序,然后使用二进制搜索。
(未测试的)
int compare_entry(ENTRY *k1, ENTRY *k2) {
int d = k1->a1 - k2->a1;
if (d == 0) {
d = k1->a2 - k2->a2;
if (d == 0) {
d = k1->a3 - k2->a3;
}
}
return d; // >0 is k1 > k2, 0 if k1 == k2, <0 if k1 < k2
}
// Derived from Wikipedia
int find(ENTRY *list, int size, ENTRY *value) {
int low = 0;
int n = size - 1;
int high = n;
while (low < high) {
int mid = low + (high - low) / 2
int cmp = compare_entry(&list[mid], value);
if (cmp < 0) {
low = mid + 1;
} else {
high = mid;
}
}
if (low < n) {
int cmp = compare_entry(&list[low], value);
if (cmp == 0) {
return low; // found item at 'low' index
}
} else {
return -1; // not found
}
}
绝对是最糟糕的情况,你会经历这个事情,10次,最后实际完成密钥比较中的所有比较。那是什么,85整数数学运算(加法,减法和1班)?
如果您的a1-a3的范围是0-100,那么您可以将您的密钥设为a1 * 10000 + a2 * 100 + a3,并进行单次比较,最坏的情况是63次整数运算。并且您的整个阵列都适合大多数现代处理器的缓存。它的内存效率很高。
您可以使用完美哈希或其他稀疏矩阵刻录内存。即使有一个完美的哈希,我敢打赌哈希计算本身在这个时候具有竞争力,考虑到乘法是昂贵的。显然,这会更难打到内存总线。