Ініціалізуйте масив за амортизованим постійним часом - як називається ця хитрість?


13

Існує ця структура даних, яка торгує продуктивністю доступу до масиву проти необхідності перебирати його під час очищення. Ви зберігаєте лічильник поколінь з кожним записом, а також глобальний лічильник поколінь. "Чітка" операція збільшує лічильник генерації. У кожному доступі ви порівнюєте лічильники місцевого та глобального поколінь; якщо вони відрізняються, значення трактується як "чисте".

Це з’явилося у цій відповіді на Stack Overflow нещодавно, але я не пам'ятаю, чи має цей трюк офіційну назву. Робить це?

Одним із випадків використання є алгоритм Діккстри, якщо потрібно розслабити лише крихітний підмножина вузлів, і якщо це потрібно робити повторно.


2
Цікавий трюк, але він має досить накладні витрати. Тож мені цікаво, для яких застосувань є очищення масиву як такої поширеної операції, за яку ціна платить? (Щире запитання!)
Йоахім Зауер

@JoachimSauer: Відредаговано.
krlmlr

Звучить дуже дорого в загальному випадку як для використання пам'яті, так і для вартості доступу. Випадок використання цієї методики повинен бути дуже конкретним.
Мартін Йорк

3
@Joachim: Він використовується для швидкого очищення буферів для рендеринга - приблизно. Вони просто мають "чіткий біт" за 64 кб або щось подібне.
DeadMG

3
@ user946850 "амортизований" означає, що ви можете довести, що дорога операція трапляється досить рідко в загальній картині, що вона не сприяє більше, ніж, наприклад, O (1)

Відповіді:


2

Вищезгаданий підхід вимагає, щоб кожна комірка могла вмістити кількість, достатньо велику, щоб утримувати кількість разів, можливо, потребувати повторної ініціалізації масиву, що є суттєвим космічним покаранням. Якщо слот здатний утримувати щонайменше одне значення, яке ніколи не буде законно записане, можна уникнути будь-якого іншого (непостійного) пробілу за рахунок додавання O(Wlg(N))часової кари, де Wкількість відокремлених проміжків масиву, записаних між операції очищення та Nрозмір масиву. Наприклад, припустимо, що одне буде зберігати цілі числа від -2,147,483,647 до 2,147,483,647 (але ніколи -2,147,483,648), і потрібно, щоб пусті елементи масиву читалися як нульові. Почніть із заповнення масиву з -2,147,483,648 (викликайте це значенняB). Читаючи слот масиву для програми, повідомте про значення Bяк нуль. Перед записи слота масиву I, перевірте чи проведено Bі якщо це так і Iбільше одиниці, зберігати нуль в слот I/4після виконання аналогічної перевірки для цього місця (і, якщо воно проведено B, I/16і т.д.).

Щоб очистити масив, почніть з Iдорівнює 0 або 1, залежно від бази масиву (алгоритм, як описано, буде працювати для будь-якого). Потім повторіть таку процедуру: якщо елемент Iє Bприростом Iі, якщо це робить, дається кратне чотирьох, діліть на чотири (припиніть, якщо ділення дає значення 1); якщо елемента Iнемає B, збережіть Bйого та помножте Iна чотири (якщо Iпочинається з нуля, множення на чотири залишить його нульовим, але оскільки пункт 0 буде порожнім, Iзбільшуватимуться).

Зауважте, що можна замінити постійну "чотири" вище на інші числа, при цьому великі величини зазвичай вимагають меншої мітки роботи, але менші значення, як правило, вимагають меншої очистки роботи; оскільки слоти масиву, які позначені тегами, повинні бути очищені, значення трьох-чотирьох майже напевно є оптимальним; оскільки значення чотири, безумовно, близьке до оптимального, краще, ніж два або вісім, і зручніше, ніж будь-яке інше число, це, здавалося б, є найбільш розумним вибором.


Досить мати лічильник версій, здатний вмістити достатню кількість послідовних скидів, перш ніж усі осередки будуть оновлені новими значеннями. На практиці байта може бути достатньо, або навіть менше в більш жорстких петлях.
9000

@ 9000: Кодекс, який покладається на таку поведінку, може бути тендітним, особливо зважаючи на те, що єдиною причиною використання такого "псевдоочисного" підходу (на відміну від простого очищення масиву) було б, якщо набір елементів, які потребують Очищення зазвичай було невеликим і змінним - пара умов, які складаються в змові збільшити ймовірність того, що предмет може звикнути, "очиститися", а потім залишатися недоторканим довгий час. Можна було б розглянути сканування масиву та фізичне очищення будь-яких старих слотів, коли лічильник збирається завернути, але ...
supercat

1
... якщо значення обтікання лічильника постійне, середній обсяг роботи для кожної чіткої операції масиву буде O (N), причому N буде розміром масиву. Не те, що таке може бути не корисним на практиці, оскільки реалізація O (N), що збільшується в 65,536 разів, все одно буде O (N), але також буде в 65,536 разів швидшою, ніж не вдосконалена . Між іншим, випадки, коли ці підходи можуть бути корисними, можуть також отримати користь від використання структури даних з розрідженим масивом, яка могла б використовувати простір O (AlgN) для утримання масиву з масивом розміром N з елементами A, які не мають порожніх елементів.
supercat

1

Я б назвав це "ленівою реініціалізацією стільникового масиву", але, схоже, немає встановленого імені (тобто, ім'я, яке широко використовується).

Алгоритм розумний, але дуже спеціалізований і застосовний у дуже вузькій області.


1

Я вважаю, що це особливий випадок запам'ятовування , за винятком випадків, що "пам'ятки" неявно "старіють" з кожним збільшенням глобального лічильника. Я здогадуюсь свого роду "зворотнє запам'ятовування".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.