Я бы просто отсортировал массив по ключу и использовал бинарный поиск.
(непроверенные)
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 целочисленных математических операции. И весь ваш массив помещается в кеш практически на любом современном процессоре. И это эффективная память.
Вы можете записать память идеальным хэшем или какой-нибудь другой разреженной матрицей. Даже с идеальным хэшем, держу пари, что само вычисление хэша на этот раз является конкурентоспособным, учитывая, что умножение стоит дорого. Очевидно, это сильнее бьет по шине памяти.