Відповідь Джо надзвичайно хороша і дає вам усі важливі ключові слова.
Вам слід пам’ятати, що лаконічні дослідження структури даних все ще знаходяться на ранній стадії, і багато результатів є в основному теоретичними. Багато запропонованих структур даних є досить складними для реалізації, але більша частина складності пов'язана з тим, що потрібно підтримувати асимптотичну складність як за розміром Всесвіту, так і за кількістю збережених елементів. Якщо будь-яке з них відносно постійне, багато складності проходить.
Якщо колекція є напівстатичною (тобто вставки рідкісні або, принаймні, малооб'ємні), то, безумовно, варто розглянути просту у впровадженні статичну структуру даних (sdarray Sadakane - прекрасний вибір) у поєднанні з оновленням кеш. В основному ви записуєте оновлення в традиційну структуру даних (наприклад, B-дерево, трие, хеш-таблиця) і періодично масово оновлюєте "основну" структуру даних. Це дуже популярна методика пошуку інформації, оскільки перевернуті індекси мають багато переваг для пошуку, але їх важко оновити на місці. Якщо це так, будь ласка, повідомте мене про це в коментарі, і я внесу зміни в цю відповідь, щоб дати вам кілька покажчиків.
Якщо вставки частіші, то я пропоную стислий хешинг. Основну ідею досить просто пояснити тут, тому я зроблю це.
Отже, основним теоретичним результатом інформації є те, що якщо ви зберігаєте елементів із всесвіту елементів, а іншої інформації немає (наприклад, немає кореляції між елементами), то вам знадобиться біти для його зберігання. (Усі логарифми є базовою-2, якщо не вказано інше.) Вам потрібно стільки бітів. Не обійтися.nulog(un)+O(1)
Тепер трохи термінології:
- Якщо у вас є структура даних, яка може зберігати дані та підтримувати ваші операції у бітах простору , ми називаємо це неявною структурою даних.log(un)+O(1)
- Якщо у вас є структура даних, яка може зберігати дані та підтримувати ваші операції в біт простору, ми називаємо це компактною структурою даних. Зауважимо, що на практиці це означає, що відносна накладність (відносно теоретичного мінімуму) знаходиться в межах постійної. Це може бути 5% накладних витрат, або 10% накладних витрат, або 10 разів накладних витрат.log(un)+O(log(un))=(1+O(1))log(un)
- Якщо у вас є структура даних, яка може зберігати дані та підтримувати ваші операції в біт простору, ми називаємо це лаконічною структурою даних.log(un)+o(log(un))=(1+o(1))log(un)
Різниця між стислим і компактним - це різниця між маленьким-ой і великим-ой. На мить ігноруючи річ з абсолютною цінністю ...
- g(n)=O(f(n)) означає, що існує константа і число така що для всіх , .cn0n>n0g(n)<c⋅f(n)
- g(n)=o(f(n)) означає, що для всіх констант існує число таке, що для всіх , .cn0n>n0g(n)<c⋅f(n)
Неофіційно великі-о-о і малі-ої є "в межах постійного коефіцієнта", але при великому-ой для вас вибирається константа (дизайнером алгоритму, виробником процесора, законами фізики чи будь-яким іншим), але мало -о, ви вибираєте постійну себе, і вона може бути такою ж маленькою, як вам подобається . Інакше кажучи, з лаконічними структурами даних відносні накладні витрати стають довільно невеликими, оскільки розмір проблеми збільшується.
Звичайно, розмір проблеми може бути величезним, щоб усвідомити відносні накладні витрати, які ви хочете, але ви не можете мати все.
Гаразд, маючи це під нашими поясами, давайте поставимо деякі цифри на проблему. Припустимо, що ключі бітних цілих чисел (тому розмір Всесвіту дорівнює ), і ми хочемо зберегти цих цілих чисел. Припустимо, що ми можемо магічно влаштувати ідеалізовану хеш-таблицю з повною заповненістю та без зайвих витрат, так що нам потрібно точно хеш-слотів.n2n2m2m
Операція пошуку дозволить хешувати бітний ключ, замаскувати бітів, щоб знайти хеш-слоти, а потім перевірити, чи відповідає значення таблиці в таблиці. Все йде нормально.nm
Така хеш-таблиця використовує біт. Чи можемо ми зробити краще, ніж це?n2m
Припустимо, що хеш-функція є зворотною. Тоді нам не потрібно зберігати весь ключ у кожному хеш-слоті. Розташування слота хеша дає вам біт хеш-значення, тому якщо ви зберегли лише решти бітів, ви можете реконструювати ключ із цих двох відомостей (місце розташування хеш-слота та значення, яке зберігається там). Тож вам знадобиться лише біт зберігання.hmn−m(n−m)2m
Якщо невеликий порівняно з , наближення Стірлінга і трохи арифметики (доказ - вправа!) Показує, що:2m2n
(n−m)2m=log(2n2m)+o(log(2n2m))
Тож ця структура даних є лаконічною.
Однак є два улови.
Перший улов - це побудова "хороших" обертових хеш-функцій. На щастя, це набагато простіше, ніж це виглядає; криптографи весь час виконують незворотні функції, лише вони називають їх "циферами". Наприклад, ви можете базувати хеш-функцію в мережі Feistel, що є простим способом побудови інвертованих хеш-функцій з неперевернутих хеш-функцій.
Друга увага полягає в тому, що справжні хеш-таблиці не є ідеальними, завдяки парадоксу Дня народження. Тож ви хочете використовувати більш складний тип хеш-таблиці, який наближає вас до повної зайнятості без розливу. Хеширование зозулі ідеально підходить для цього, оскільки дозволяє теоретично наблизитись до ідеалу і досить близько на практиці.
Для хешування зозулі потрібно декілька хеш-функцій, і вона вимагає, щоб значення в хеш-слотах були позначені тегами, за допомогою якої використовувалася хеш-функція. Отже, якщо ви використовуєте чотири хеш-функції, наприклад, вам потрібно зберегти додаткові два біта у кожному хеш-слоті. Це все ще є лаконічним у міру зростання , тому це не є проблемою на практиці, і все ще б'є зберігання цілих клавіш.m
О, ви також можете подивитися на дерева Емде Боаса.
БІЛЬШЕ МИСЛІВ
Якщо десь навколо , то приблизно , тож (ще раз) припускаючи, що немає ніякої подальшої кореляції між величинами, ви в основному не можете зробити жодне краще, ніж бітний вектор. Ви зауважите, що вищевказане рішення хешування ефективно вироджується в цьому випадку (ви в кінцевому підсумку зберігаєте один біт на хеш-слот), але дешевше просто використовувати ключ як адресу, а не використовувати хеш-функцію.nu2log(un)u
Якщо дуже близький до , вся література про стислі структури даних радить вам інвертувати сенс словника. Зберігайте значення, які не зустрічаються у наборі. Однак тепер вам ефективно потрібно підтримувати операцію видалення, а для збереження лаконічної поведінки також потрібно мати змогу скоротити структуру даних, оскільки «додається більше елементів». Розширення хеш-таблиці - це добре зрозуміла операція, але укладання контрактів - це не так.nu