Додавання елементів до відсортованого масиву


31

Який би був найшвидший спосіб зробити це (з алгоритмічної точки зору, а також з практичної справи)?

Я щось думав у наступних напрямках.

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

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

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

Як це найкраще зробити?


1
Найшвидший спосіб, якщо доводиться це робити часто, - це не використовувати масив в першу чергу.
reinierpost

Ви маєте на увазі самоврівноваження бінарного дерева?
soandos

Так, можливо; дивіться відповіді ...
reinierpost

Відповіді:


25

Підраховуємо кількість елементів читання та запису масиву. Для сортування бульбашок вам потрібно доступу (початкове записування до кінця, потім, в гіршому випадку, два читання і два записи, щоб зробити свопів). Для здійснення двійкового пошуку нам потрібно ( для двійкового пошуку, тоді, в гіршому випадку, для зміщення елементів масиву праворуч, потім 1 для запису елемента масиву в її правильне положення).n 2 log n + 2 n + 1 2 log n 2 n1+4нн2журналн+2н+12журналн2н

Отже, обидва способи мають однакову складність для реалізації масивів, але метод двійкового пошуку вимагає меншої кількості доступів до масиву в довгостроковій перспективі ... асимптотично, вдвічі менше. Є, природно, інші фактори.

Насправді, ви можете використовувати кращі реалізації та рахувати лише фактичний доступ до масиву (не доступ до елементу, який потрібно вставити). Ви можете зробити для сортування бульбашок та для двійкового пошуку ... так що якщо реєстрація / кеш-доступ дешевий, а доступ до масиву дорогий, пошук з кінця та зміщення по шляху (розумніший міхур сортування для вставки) може бути кращим, хоча не асимптотично.log n + 2 n + 12н+1журналн+2н+1

Кращим рішенням може бути використання іншої структури даних. Масиви дають вам доступ до O (1) (випадковий доступ), але вставки та видалення можуть коштувати. Хеш-таблиця може мати вставки та видалення O (1), доступ коштуватиме. Інші варіанти включають BST та купи тощо. Можливо, варто врахувати потреби у застосуванні для додавання, видалення та доступу та вибрати більш спеціалізовану структуру.

Зауважте також, що якщо ви хочете додати елементів до відсортованого масиву з елементів, гарною ідеєю може бути ефективне сортування елементів, а потім об'єднати два масиви; Крім того, відсортовані масиви можуть бути побудовані ефективно, наприклад, за допомогою купи (сортування купи).н ммнм


1
"Таблиця хешів може мати O (1) вставок і видалень" - зазвичай амортизується.
Рафаель

8
Амортизовані очікувані .
JeffE

BST має для пошуку та вставки (wikipedia), тож чому це не найкращий вибір тут? для пошуку та вставки. O ( 2 l o g n )О(лог н)О(2 лог н)
Кашяп

8

Якщо у вас є якісь причини не використовувати купу, подумайте про використання сортування вставки замість сортування бульбашок. Краще, коли у вас є кілька несортованих елементів.


8

Оскільки ви використовуєте масив, для вставки елемента коштує - наприклад, коли ви щось додаєте в середину масиву, вам доведеться перемістити всі елементи після нього на один, щоб масив залишався сортованим .О(н)

Найшвидший спосіб дізнатися, куди помістити предмет, як ви вже згадали, - двійковий пошук, який є , тому загальна складність буде , яка знаходиться на порядок .O ( n + lg n ) O ( n )О(lgн)О(н+lgн)О(н)

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

У будь-якому разі, я не бачу причин витягувати міхур з цієї проблеми.


2
Не дуже корисно залишатись на рівні при порівнянні алгоритмів, які займають лінійний час. О
Рафаель

+1 за те, що він хитрий .. :-)
Кашяп

4

Патрік87 все це дуже добре пояснив. Але однією додатковою оптимізацією ви могли б скористатися чимось на зразок кругового буфера: ви можете переміщувати елементи праворуч від положення вставленого елемента праворуч, як зазвичай. Але ви також можете переміщувати предмети ліворуч від правильного положення ліворуч. Для цього вам потрібно розглядати масив як круговий, тобто останній елемент знаходиться безпосередньо перед першим, і він також вимагає від вас зберегти індекс, де зараз починаються елементи.

Якщо це зробити, це може означати, що ви робите приблизно вдвічі більше доступів до масиву (припускаючи рівномірний розподіл індексів, які ви вставляєте). У разі здійснення двійкового пошуку, щоб знайти позицію, неважливо вибрати, чи слід переходити вліво чи вправо. У разі сортування бульбашок перед початком роботи потрібно правильно «здогадатися». Але зробити це просто: просто порівняйте вставлений елемент з медіаною масиву, що можна зробити в одному доступі до масиву.


4

Я ефективно використав алгоритм сортування вкладок для цієї проблеми. У свій час у нас виникла проблема продуктивності з об’єктом хеш-таблиці, я написав новий об’єкт, який використовував бінарний пошук замість цього, що значно підвищив продуктивність. Щоб зберегти список відсортований, він би відслідковував кількість елементів, доданих з моменту останнього сортування (тобто кількість несортованих елементів), коли список потрібно було сортувати за запитом пошуку, він здійснив сортування вставки або швидкого сортування залежно на відсоток відсортованих предметів. Використання сортування вставок було ключовим у покращенні продуктивності.


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