Коли у вас дійсно великий файл і багато елементів у ньому, але найпоширеніший елемент дуже поширений - трапляється частина часу - ви можете його знайти в лінійному часі з просторовими словами ( константа в нотації дуже мала, в основному 2, якщо ви не рахуєте сховища для допоміжних речей, таких як хешування). Більше того, це чудово спрацьовує із зовнішнім сховищем, оскільки файл обробляється послідовно один за одним, а алгоритм ніколи не «озирається назад». Один із способів зробити це - за допомогою класичного алгоритму Місри та Гріса, див. Ці конспекти лекцій . Зараз ця проблема відома як проблема важких нападників (частими елементами є важкі нападники).O ( k ) O ( )> 1 / кО ( k )О ( )
Припущення, що найчастішим елементом виявляється частина часу для невеликої кількості, може здатися сильним, але це певним чином необхідно! Тобто, якщо у вас буде послідовний доступ до вашого файлу (і якщо файл величезний випадковий доступ буде занадто дорогим), будь-який алгоритм, який завжди знаходить найчастіший елемент у постійній кількості проходів, буде використовувати лінійний простір у кількості елементів . Отже, якщо ви щось не припускаєте про вхід, ви не можете перемогти хеш-таблицю. Припущення про те, що найчастіший елемент дуже часто є, можливо, найбільш природним способом подолати негативні результати.к> 1 / кк
Ось ескіз для , тобто коли є один елемент, який зустрічається більше половини часу. Цей особливий випадок відомий як алгоритм більшості голосів і пояснюється Боєром та Муром. Ми збережемо один елемент і один рахунок. Ініціалізуйте кількість до 1 і збережіть перший елемент файлу. Потім обробіть файл послідовно:k =2
- якщо поточний елемент файлу такий же, як збережений елемент, збільште кількість на одиницю
- якщо поточний елемент файлу відрізняється від збереженого елемента, зменшіть кількість на одиницю
- якщо оновлений кількість дорівнює 0, "вимкніть" збережений елемент і збережіть поточний елемент файлу; збільшити кількість до 1
- переходимо до наступного елемента файлу
Трохи задумавшись над цією процедурою, переконайте вас, що якщо існує елемент "більшості", тобто такий, який відбувається більше половини часу, то цей елемент буде збереженим елементом після обробки всього файлу.
Загальних , ви тримаєте елементи і розраховує, і ініціалізувати елементи до першого різних елементів файлу і розраховує на кількість разів , кожен з цих елементів з'являється , перш ніж ви бачите -й виразний елемент. Тоді ви запускаєте по суті ту саму процедуру: кількість елементів збільшується щоразу, коли виникає, кількість елементів зменшується, якщо зустрічається елемент, який не зберігається, а коли деякий підрахунок дорівнює нулю, цей елемент витісняється на користь поточний елемент файлу. Це алгоритм Місра-Гріса.k - 1 k - 1 k kкk -1k -1кк
Звичайно, ви можете використовувати хеш-таблицю для індексації збережених елементів . Після припинення цей алгоритм гарантовано повертає будь-який елемент, який зустрічається більше частки часу. Це, по суті, найкраще, що ви можете зробити з алгоритмом, який робить постійну кількість проходів по файлу і зберігає лише слова.1 / k O ( k )k -11 / кО ( к)
к1 / кk - 1