Hashtables это путь.
Они имеют среднюю O (1) сложность для поиска, вставки и удаления!
Они, как правило, занимают больше памяти, чем деревья, но гораздо быстрее.
Поскольку вы работаете только с 32-битным целым числом (вы, конечно, можете конвертировать IP в 32-битное целое), все будет удивительно просто и быстро.
Вы можете просто использовать отсортированный массив. Стоимость вставки и удаления равна O (n), но поиск равен O (log n), и особенно объем памяти составляет всего 4 байта для каждого ip.
Реализация очень проста, возможно, слишком много: D
Двоичные деревья имеют сложность O (log n) для поиска, вставки и удаления.
Однако простого бинарного дерева было бы недостаточно, вам нужно дерево AVL или красное черное дерево, которое может быть очень раздражающим и сложным для реализации.
Деревья AVL и RBT могут уравновешивать себя, и нам это нужно, потому что несбалансированное дерево будет иметь наихудшую временную сложность O (n) для поиска, что аналогично простому связанному списку!
Если вместо одного и уникального IP-адреса вам нужно запретить диапазоны IP-адресов, возможно, вам нужна Патриция Три, также называемая Radix Tree, они были изобретены для словарей и словарей IP.
Тем не менее, эти деревья могут быть медленнее, если не хорошо написаны \ сбалансированы.
Hashtable всегда лучше для простых поисков! Они слишком быстрые, чтобы быть реальными:)
Теперь о синхронизации:
Если вы заполняете черный список только один раз при запуске приложения, вы можете использовать простую хэш-таблицу только для чтения (или основное дерево), у которой нет проблем с многопоточностью и блокировкой.
Если вам нужно обновлять его не очень часто, я бы посоветовал вам использовать блокировки чтения-записи.
Если вам нужны очень частые обновления, я бы посоветовал вам использовать параллельную хеш-таблицу.
Предупреждение: не пишите свои собственные, они очень сложные и подвержены ошибкам, найдите реализацию в Интернете!
Они часто используют (относительно) новые атомарные операции CAS новых процессоров (CAS означает «Сравнить» и «Поменять местами»). Это специальный набор инструкций или последовательность инструкций, которые позволяют сравнивать и заменять 32-битные или 64-битные поля в памяти за одну атомарную операцию без необходимости блокировки.
Их использование может быть сложным, потому что вы должны очень хорошо знать свой процессор, свою операционную систему, свой компилятор и сам алгоритм, что противоречит интуиции.
См. http://en.wikipedia.org/wiki/Compare-and-swap для получения дополнительной информации о CAS.
Было изобретено параллельное дерево AVL, но оно настолько сложное, что я действительно не знаю, что сказать об этом :), например, http://hal.inria.fr/docs/00/07/39/31/PDF/RR-2761.pdf
Я только что обнаружил, что параллельное основание существует:
ftp: //82.96.64.7/pub/linux/kernel/people/npiggin/patches/lockless/2.6.16-rc5/radix-intro.pdf, но это тоже довольно сложно.
Параллельно отсортированных массивов, конечно, не существует, для обновления вам нужна блокировка чтения-записи.
Учтите также, что объем памяти, необходимый для обработки неконкурентной хеш-таблицы, может быть довольно небольшим: для каждого IP-адреса вам нужно 4 байта для IP-адреса и указателя.
Вам также нужен большой массив указателей (или 32-битных целых чисел с некоторыми хитростями), размер которых должен быть простым числом больше, чем количество элементов, которые должны быть сохранены.
Hashtables, конечно, может также изменять свой размер, если требуется, но они могут хранить также больше элементов, чем эти простые числа, за счет более медленного времени поиска.
Как для деревьев, так и для хеш-таблицы сложность пространства линейна.
Я надеюсь, что это многопоточное приложение, а не многопроцессорное (fork).
Если это не многопоточность, вы не можете быстро и надежно разделить часть памяти.