Масив проти пов'язаного списку


200

Чому хтось хоче використовувати зв'язаний список через масив?

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

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

Це питання не є дублікатом цього питання, оскільки інше запитання стосується конкретного класу Java, тоді як це питання стосується загальних структур даних.


1
Пов'язане - Коли використовувати LinkedList <> over ArrayList <>? - це Java, але масиви (ArrayList) та пов'язані списки, мабуть, мають однакову продуктивність на будь-якій мові.
Бернхард Баркер


1
@rootTraveller Насправді це питання було б дублікатом цього питання, оскільки моє запитання було розміщено першим.
Оноріо Катенац

Відповіді:


147
  • Простіше зберігати дані різного розміру у пов'язаному списку. Масив передбачає, що кожен елемент має однаковий розмір.
  • Як ви вже згадували, пов'язаний список легше органічно рости. Розмір масиву потрібно знати заздалегідь або створити його знову, коли він повинен зростати.
  • Переміщення пов'язаного списку - це лише питання зміни того, що вказує на що. Переміщення масиву складніше і / або займає більше пам’яті.
  • Поки всі ваші ітерації відбуваються в контексті "передбачення", ви не втрачаєте жодної продуктивності в ітерації.

19
Як по-різному ставляться до предметів різного розміру? Зв'язаний список або використовує фіксовану структуру з наступним полем (вимагає фіксованого розміру), або зберігає вказівник на дані в машині (змінна величина ОК). Обидва підходи з вектором так само прості. Те саме для перетасування.
Брайан

32
Я б сказав, що перетасування масиву є менш складним.
Х'ю Аллен

23
Ця відповідь є невірною та оманливою. (за винятком того, що потрібно знати розмір масиву, коли ви заявляєте про це)
Роберт Полсон,

35
Чи не буде повторення пов'язаного списку повільніше через локальність даних?
Фірас Ассаад

6
@ Rick, вектори зазвичай перерозподіляють потрібний їм простір, щоб їм не потрібно виділяти новий простір щоразу, коли розмір збільшується. Результат полягає в тому, що вектори, як правило, набагато менш об'ємні, а не більше пов'язаних списків.
Вінстон Еверт

179

Ще однією вагомою причиною є те, що пов'язані списки добре піддаються ефективним багатопотоковим реалізаціям. Причиною цього є те, що зміни, як правило, є локальними - торкаються лише вказівника або двох для вставки та видалення в локалізованій частині структури даних. Отже, у вас може бути багато потоків, що працюють над тим самим пов'язаним списком. Навіть більше, можна створити версії без замків, використовуючи операції типу CAS, і взагалі уникнути великої ваги.

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

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


9
Олексій - ось цікавий розгляд, який мені ніколи не прийшов у голову. Дуже гарна відповідь. Я б двічі підтримав вас, якби міг. :-)
Оноріо Катенач

5
Погляньте на пропускні списки (зокрема ConcurrentSkipListMap на Java 6), щоб мати гарне уявлення про те, куди ви можете піти з цим. CSLM - це відсортована, паралельна карта із відмінною продуктивністю. Набагато краще, ніж синхронізований TreeMap. tech.puredanger.com/2007/10/03/skip-lists
Алекс Міллер

... за винятком того, що ConcurrentSkipListMapабо ConcurrentSkipListMapНЕ списки, навіть якщо «Список» відбувається де - то в їх назві. Для обох потрібні ключі, які будуть відсортовані та унікальні. Якщо вам потрібна List, тобто структура даних, яка дозволяє дублювати елементи в довільному порядку, це не підходить, і вам доведеться пройти великі довжини, щоб зробити структуру даних, як LinkedListпаралельно оновлену річ. Якщо вам потрібна лише паралельна черга чи деке, ну так, є навіть існуючі приклади, але паралельний List... Я не переконаний, що це навіть можливо.
Холгер

128

У Вікіпедії є дуже хороший розділ про відмінності.

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

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

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

http://en.wikipedia.org/wiki/Linked_list


4
Це ідеальна відповідь. Коротко описує переваги та недоліки обох.
Рік

дякую)) мертвий простий, але я його не бачив у вікі)
Тимур Файзрахманов

58

Додам ще одне - списки можуть виступати як суто функціональні структури даних.

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

a = (1 2 3 4, ....)
b = (4 3 2 1 1 2 3 4 ...)
c = (3 4 ...)

тобто:

b = 4 -> 3 -> 2 -> 1 -> a
c = a.next.next  

без копіювання даних, на які вказують, aв bі c.

Ось чому вони настільки популярні у функціональних мовах, які використовують незмінні змінні - prependі tailоперації можуть відбуватися вільно без копіювання вихідних даних - дуже важливі функції, коли ви ставитесь до даних як до незмінних.


4
Ще один дуже цікавий розгляд, якого я ніколи не придумав би. Дякую.
Оноріо Катенац

Як я можу це зробити в python?
переобмін

29

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

Але, чесно кажучи, я ніколи не використовував пов'язаний список. Щоразу, коли мені потрібні були швидкі вставки та видалення, мені також потрібен швидкий пошук, тому я перейшов до HashSet або Словника.


2
Дуже вірно, вставлення та видалення відбувається після пошуку більшої частини часу, тому потрібно враховувати і кількість часових складностей.
М. А. Хоссайн Тону

28

Об'єднання двох пов'язаних списків (особливо двох подвійно пов'язаних списків) набагато швидше, ніж об'єднання двох масивів (якщо припустити, що злиття є руйнівним). Перший приймає O (1), останній приймає O (n).

EDIT: Для уточнення, я мав на увазі "злиття" тут у невпорядкованому розумінні, а не як у вигляді злиття. Можливо, "об'єднання" було б кращим словом.


2
Тільки якщо ви просто додаєте один список до іншого. Якщо ви насправді об'єднуєте два відсортовані списки, то для журналу знадобиться більше, ніж O (1).
Гермс

3
@Herms, але ви можете об'єднати два відсортовані зв'язані списки, не виділяючи зайвої пам’яті, просто пройшовши обидва списки та встановивши покажчики відповідним чином. Об'єднання двох масивів зазвичай займає хоча б один додатковий масив.
Пол Томблін

1
Так, злиття списків є більш ефективною пам'яттю, але це було насправді не тим, що я коментував. Скажімо, що об'єднання пов'язаних списків є O (1), дуже неправдивим є без уточнення справи.
Гермс

Списки злиття @Herms не є більш ефективними в пам'яті, ніж об'єднання масивів під будь-яку розумну модель даних.
Олексій Аверченко

2
Олексій Аверченко: Об’єднання двох списків або навіть сортування двох упорядкованих списків можна зробити на місці з пам'яттю O (1). Об'єднання двох масивів займає O (n) пам'ять обов'язково, якщо тільки масиви вже не суміжні в пам'яті. Думаю, що ви орієнтуєтесь на те, що список n елементів та масив n елементів займають O (n) пам'яті, але коефіцієнт вищий для пов'язаних списків.
чемпіон

17

Широко недооцінений аргумент для ArrayList і проти LinkedList полягає в тому, що LinkedLists незручно під час налагодження . Час, який витрачають розробники технічного обслуговування на розуміння програми, наприклад, на пошук помилок, збільшується, а IMHO іноді не виправдовує наносекунд в покращенні продуктивності або байтах у споживанні пам'яті у корпоративних аплікатонах. Іноді (ну, звичайно, це залежить від типу додатків), краще витратити кілька байт, але мати додаток, який є більш ретельним або простішим для розуміння.

Наприклад, у середовищі Java та за допомогою налагоджувача Eclipse налагодження ArrayList виявить дуже просту для розуміння структуру:

arrayList   ArrayList<String>
  elementData   Object[]
    [0] Object  "Foo"
    [1] Object  "Foo"
    [2] Object  "Foo"
    [3] Object  "Foo"
    [4] Object  "Foo"
    ...

З іншого боку, перегляд вмісту LinkedList і пошук конкретних об'єктів стає кошмаром, що натискає на Розгорнуте дерево, не кажучи вже про когнітивні накладні витрати, необхідні для фільтрації внутрішніх справ LinkedList:

linkedList  LinkedList<String>
    header  LinkedList$Entry<E>
        element E
        next    LinkedList$Entry<E>
            element E   "Foo"
            next    LinkedList$Entry<E>
                element E   "Foo"
                next    LinkedList$Entry<E>
                    element E   "Foo"
                    next    LinkedList$Entry<E>
                    previous    LinkedList$Entry<E>
                    ...
                previous    LinkedList$Entry<E>
            previous    LinkedList$Entry<E>
        previous    LinkedList$Entry<E>

17

Перш за все, в C ++ пов'язаних списках не повинно бути більше проблем, ніж з масивом. Ви можете використовувати std :: list або список покажчиків підсилення для пов'язаних списків. Ключові проблеми пов'язаних списків проти масивів - це додаткове місце, необхідне для покажчиків та жахливий випадковий доступ. Ви повинні використовувати пов'язаний список, якщо ви

  • вам не потрібен випадковий доступ до даних
  • ви будете додавати / видаляти елементи, особливо в середині списку

14

Для мене це так,

  1. Доступ

    • Пов'язані списки дозволяють отримати лише послідовний доступ до елементів. Таким чином, алгоритмічні складності є порядком O (n)
    • Масиви дозволяють випадковий доступ до його елементів, і, таким чином, складність є порядком O (1)
  2. Зберігання

    • Пов'язані списки потребують додаткового сховища для посилань. Це робить їх непрактичним для списків невеликих елементів даних, таких як символи або булеві значення.
    • Для масивів не потрібно додаткового сховища для вказівки на наступний елемент даних. До кожного елемента можна отримати доступ через індекси.
  3. Розмір

    • Розмір пов'язаних списків динамічний за своєю природою.
    • Розмір масиву обмежується оголошенням.
  4. Вставка / видалення

    • Елементи можна вставляти та видаляти у пов'язані списки на невизначений термін.
    • Введення / видалення значень у масивах дуже дороге. Це вимагає перерозподілу пам'яті.

У вас є 2 число 2, і 2 число 3 :)
Хенгаме

Ми можемо оголосити порожній масив, а потім продовжувати додавати дані, як потрібно. Як це все-таки має фіксований розмір?
HebleV

11

Дві речі:

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

Ніколи не кодуйте пов'язаний список при використанні C ++. Просто використовуйте STL. Наскільки це важко реалізувати, ніколи не повинно бути причиною вибору однієї структури даних над іншою, оскільки більшість з них вже реалізовані там.

Що стосується фактичних відмінностей між масивом і пов'язаним списком, то для мене головне - як ви плануєте використовувати структуру. Я буду використовувати термін вектор, оскільки це термін для змінного масиву в C ++.

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

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

Видалити елемент зі списку досить просто, оскільки вам потрібно просто перервати пару посилань, а потім з'єднати їх назад. Видалення елемента з вектора може бути швидшим або повільнішим, залежно від того, якщо ви дбаєте про замовлення. Переміщення останнього предмета зверху на предмет, який ви хочете вилучити, відбувається швидше, а переміщення всього після нього відбувається повільніше, але зберігає замовлення.


Як я казав комусь вище, я просто намагався ставити питання так, як воно було мені поставлено. Я б ніколи не використовував масив (або пов’язаний список власноруч) у C ++ - я б використовував версії STL обох цих.
Оноріо Катенац

10

Ерік Ліпперт нещодавно опублікував посаду з однієї з причин, що масиви слід використовувати консервативно.


2
Справді, хороший пост, але не доречний у пов'язаному списку та дискусії з масиву.
Роберт Полсон,

2
Я б припустив, що значна частина статті Еріка є актуальною, оскільки вона обговорює як недоліки масивів, так і переваги списків, незалежно від реалізації списку.
Беван

8

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


7

Ось швидкий: Вилучення предметів відбувається швидше.


7

Пов'язаний список особливо корисний, коли колекція постійно зростає та скорочується. Наприклад, важко уявити, намагаючись реалізувати Чергу (додати до кінця, видалити з фронту) за допомогою масиву - ви витратите весь свій час на зміщення речей. З іншого боку, це тривіально із пов'язаним списком.


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

3
І називається "круговим буфером", якщо ви хочете переглянути його в улюбленому посиланні алгоритму.
Стів Джессоп

7

Крім додавання та видалення з середини списку, мені більше подобаються пов’язані списки, оскільки вони можуть динамічно рости та скорочуватися.


6
Вектори (= в основному масиви) теж можуть це зробити, і амортизована вартість для них зазвичай менша, ніж для списків через проблеми, що стосуються місцевості.
Конрад Рудольф

7

Ніхто більше не кодує свій власний пов'язаний список. Це було б нерозумно. Припущення про те, що використання зв'язаного списку займає більше коду, просто неправильне.

У наші дні складання зв'язаного списку - лише вправа для студентів, щоб вони могли зрозуміти концепцію. Натомість усі використовують заздалегідь створений список. В C ++, виходячи з опису в нашому запитанні, це, мабуть, означало би вектор stl ( #include <vector>).

Тому вибір пов’язаного списку проти масиву - це цілком зважування різних характеристик кожної структури щодо потреб вашого додатка. Подолання додаткового навантаження на програмування повинно мати нульовий вплив на рішення.


2
Er..umm .. std :: вектор - це масив, а не пов'язаний список. Стандартний пов'язаний список - це, ну, std :: list.
Джеймс Курран

1
так, але я думаю, що вектор є ближчим до того, що вимагає оп - заміни динамічного масиву.
Джоель Куехорн

@Joel, я просто намагався пов'язати питання, як це мені поставив цей хлопець, який намагається вивчити C ++. Я також не зациклювався на кодуванні мого власного пов'язаного списку, але саме так він запитав мене. :-)
Оноріо Катенач

У обмежених пам’яттю середовищах (мікроконтролерах), для яких існують спеціальні компілятори, реалізована не вся мова (наприклад, контейнери в C ++). Тож, можливо, вам доведеться кодувати власний пов'язаний список. nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
Minh Tran

6

Це дійсно питання ефективності: накладні витрати на вставлення, вилучення або переміщення (де ви не просто замінюєте) елементів всередині пов'язаного списку мінімальні, тобто сама операція O (1), вірші O (n) для масиву. Це може істотно змінитись, якщо ви активно працюєте у списку даних. Ви вибрали типи даних, виходячи з того, як ви будете працювати над ними, і вибрали найбільш ефективний алгоритм, який ви використовуєте.


6

Масиви мають сенс, де буде відома точна кількість елементів і де пошук за індексом має сенс. Наприклад, якби я хотів зберегти точний стан мого відеовиходу в даний момент без стиснення, я, ймовірно, використовував би масив розмірів [1024] [768]. Це забезпечить мені саме те, що мені потрібно, і список буде набагато, набагато повільніше, щоб отримати значення заданого пікселя. У місцях, де масив не має сенсу, є, як правило, кращі типи даних, ніж перелік для ефективної обробки даних.


6

Список пов’язаних масивів проти:

  1. Розподіл пам’яті масиву інколи не вдасться через фрагментовану пам'ять.
  2. Керування краще в масивах, оскільки всі елементи виділяються суміжним простором пам'яті.
  3. Кодування складніше, ніж масиви.
  4. У зв'язаному списку немає обмежень щодо розміру, на відміну від масивів
  5. Вставка / видалення швидше у пов'язаному списку та швидший доступ у масивах.
  6. Пов'язаний список кращий з точки зору з декількома потоками

-1: Все це потрібно обґрунтувати, а не просто перерахувати.
Джон Сондерс

Кожен пункт уже був пояснений у відповідях вище. Будучи пізнім, я не мав іншого виходу, ніж перерахувати. BTW, кого б ви хотіли пояснити?
AKS

Якщо вони вже пояснили, то чому ви відповідаєте?
Джон Сондерс

2
Так що це дасть вам узагальнений вигляд дискусії. І мені подобаються такі типи відповідей, що мені не доведеться читати одне і те ж пояснення знову і знову. І я це зробив для тих людей, які мають такий же стиль мислення, як і мій. Різні ppl мають різні стилі. Нічого нового.
AKS

3

оскільки масиви мають статичний характер, тому всі операції, такі як розподіл пам'яті, відбуваються лише під час компіляції. Тому процесору доводиться докладати менше зусиль під час його виконання.


3

Припустимо, у вас є впорядкований набір, який ви також хочете змінити, додаючи та видаляючи елементи. Крім того, вам потрібно вміти зберігати посилання на елемент таким чином, щоб згодом ви могли отримати попередній або наступний елемент. Наприклад, список справ або набір абзаців у книзі.

Спершу слід зазначити, що якщо ви хочете зберегти посилання на об'єкти поза самим набором, ви, швидше за все, збережете вказівник у масиві, а не зберігати самі об'єкти. В іншому випадку ви не зможете вставити в масив - якщо об’єкти вбудовані в масив, вони перемістяться під час вставки і будь-які вказівники на них стануть недійсними. Те саме стосується індексів масиву.

Вашою першою проблемою, як ви вже відзначили, є вбудований список, що дозволяє вставляти в O (1), але масив, як правило, вимагає O (n). Цю проблему можна частково подолати - можна створити структуру даних, яка надає подібно до порядкового інтерфейсу доступ до масиву, де і читання, і запис є, в гіршому випадку, логарифмічними.

Ваша друга, і більш серйозна проблема полягає в тому, що заданим елементом пошуку наступного елемента є O (n). Якщо набір не був змінений, ви можете зберегти індекс елемента як посилання замість вказівника, таким чином зробивши операцію find-next операцією O (1), але так як це все, що у вас є, це вказівник на сам об’єкт і ніяк визначити його поточний індекс у масиві, відмінному від сканування всього "масиву". Це непереборна проблема для масивів - навіть якщо ви можете оптимізувати вставки, ви нічого не можете зробити для оптимізації операцій пошуку наступного типу.


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

1
У розділі "Динамічний масив / Vriants" є кілька матеріалів у Вікіпедії. Але це не зовсім те, що я мав на увазі ... Уявіть структуру, подібну до дерева b +, зі сторінками, але без клавіш, натомість кожна проміжна сторінка запам'ятовує, скільки елементів є в кожній з підсторінок, тоді як на аркушах аркушів просто міститься елементів у невеликому масиві. Під час вставлення елемента на сторінку з листами потрібно перемістити ~ половину сторінки, щоб звільнити місце, а потім підняти та оновити кількість елементів на всіх сторінках предків. Шукаючи елемент #N, просто додайте кількість підрядних сторінок, доки ви не перетнете N, а потім
спустіться

3

У масиві ви маєте право отримати доступ до будь-якого елемента за час O (1). Таким чином, його підходить для таких операцій, як Бінарний пошук Швидкий сортування, і т.д. Обидва мають переваги, а також недоліки, і віддати перевагу одному над іншим зводиться до того, що ви хочете реалізувати.

- Більш важливе питання - чи може ми мати гібрид обох. Щось на зразок того, що python та perl реалізують як списки.


3

Пов'язаний список

Її краще, якщо мова йде про вставку! По суті, це те, що він має справу з покажчиком

1 -> 3 -> 4

Вставка (2)

1 ........ 3 ...... 4
..... 2

Нарешті

1 -> 2 -> 3 -> 4

Одна стрілка з 2 балів на 3 та стрілка 1 бала на 2

Просто!

Але від Array

| 1 | 3 | 4 |

Вставка (2) | 1 | 3 | | 4 | | 1 | | 3 | 4 | | 1 | 2 | 3 | 4 |

Ну будь-хто може уявити різницю! Тільки для 4 індексу ми виконуємо 3 кроки

Що робити, якщо довжина масиву одно мільйон? Чи ефективний масив? Відповідь НІ! :)

Те ж саме стосується видалення! У пов'язаному списку ми можемо просто використовувати вказівник і звести нанівець елемент і далі в класі об’єктів! Але для масиву нам потрібно виконати shiftLeft ()

Сподіваюся, що це допомагає! :)


3

Зв'язаний список є більш корисним для підтримки, ніж масив, він також потребує додаткового зберігання пам'яті, всі ці пункти узгоджені. Але є кілька речей, які масив не може зробити. У багатьох випадках припустімо, що ви хочете масив довжиною 10 ^ 9, ви не можете його отримати, оскільки отримання одного безперервного місця пам'яті повинно бути там. Тут пов'язаний список може бути рятівником.

Припустимо, ви хочете зберігати кілька речей з даними, щоб їх можна було легко розширити у пов'язаному списку.

Контейнери STL зазвичай мають зв'язаний перелік списку поза сценою.


3

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

2- розмір пов'язаного списку може збільшуватися або зменшуватися під час виконання, так що немає втрати пам'яті. У випадку з масивом багато втрати пам’яті, як, наприклад, якщо ми оголосимо масив розміром 10 і збережемо в ньому лише 6 елементів, то простір з 4 елементів витрачається даремно. У пов'язаному списку такої проблеми немає, оскільки пам'ять виділяється лише за потреби.

3- Структури даних, такі як стек і черги, можна легко реалізувати за допомогою пов'язаного списку.


2

Єдина причина використовувати зв'язаний список - це те, що вставити елемент легко (видалити також).

Дезаватизація може полягати в тому, що покажчики займають багато місця.

А щодо цього кодування складніше: зазвичай вам не потрібен список, пов'язаний з кодом (або лише один раз), вони включаються до STL, і це не так складно, якщо вам все-таки це потрібно зробити.


2
Покажчики займають багато місця? Не зовсім. Якщо ви зберігаєте пов’язаний список булевих, тоді впевнено, у відсотках розумні покажчики займають багато місця. Але якщо ви зберігаєте складні об'єкти (що, як правило, так), то покажчики, ймовірно, будуть незначними.
Гермс

забув усмішку :) Але сказав "міг" не "є".
користувач15453

1

Я також думаю, що список посилань краще, ніж масиви. тому що ми проходимо в списку посилань, а не в масивах


1

Залежно від вашої мови можна врахувати деякі з цих недоліків та переваг:

C Мова програмування : Під час використання зв'язаного списку (як правило, через структурні вказівники), слід звернути особливу увагу на те, що у вас не протікає пам'ять. Як було сказано раніше, пов'язані списки легко перетасувати, тому що всі робили це зміна покажчиків, але чи будемо ми пам’ятати, щоб звільнити все?

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


1

Чому зв'язаний список через масив? Ну, як дехто вже говорив, більша швидкість вставки та видалення.

Але, можливо, нам не доведеться жити за межами будь-якого, і отримувати все найкраще одночасно ... так?

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

Якщо у вас дійсно великий масив, ви можете комбінувати його з іншим, набагато меншим масивом або зв'язаним списком, де менший містить 20, 50, 100 останніх використовуваних елементів. Якщо потрібного немає у скороченому списку чи масиві, ви переходите до великого масиву. Якщо ви знайдете там, ви можете додати його до меншого пов'язаного списку / масиву з припущенням, що «речі, які нещодавно використовували, найбільш схожі на повторне використання» (і так, можливо, зіткнення найменш використаного елемента зі списку). Що справедливо у багатьох випадках і вирішує проблему, яку мені довелося вирішити в модулі перевірки дозволів безпеки .ASP, з легкістю, елегантністю та вражаючою швидкістю.


1

Хоча багато хто з вас торкнулися основних adv./dis зв'язаного списку проти масиву, більшість порівнянь - це те, наскільки один краще / гірше, ніж інший. Ви можете робити випадковий доступ у масиві, але це неможливо у пов'язаному списку та інших. Однак це припустимо, що списки посилань і масив будуть застосовані в подібній програмі. Однак правильною відповіддю має бути те, яким чином перелік посилань буде віддавати перевагу над масивом та навпаки у певному застосуванні програми. Припустимо, ви хочете реалізувати програму словника, що б ви використовували? Масив: ммм, це дозволить легко знайти через двійковий пошук та інші пошукові альго .. але давайте подумаємо, як список посилань може бути кращим .. Скажіть, ви хочете шукати "Blob" у словнику. Чи має сенс мати список посилань A-> B-> C-> D ---->

A -> B -> C -> ...Z
|    |    |
|    |    [Cat, Cave]
|    [Banana, Blob]
[Adam, Apple]

Тепер вищенаведений підхід кращий чи плоский масив [Адам, Яблуко, Банан, Блоб, Кіт, Печера]? Чи можливо це навіть з масивом? Отже, головна перевага списку посилань полягає в тому, що ви можете мати елемент не лише вказувати на наступний елемент, але і на якийсь інший список посилань / масив / купу / або будь-яке інше місце пам'яті. Масив - це одна плоска суміжна пам'ять, розрізана на блоки розміром елемента, який він збирається .. Список посилань з іншого боку - це шматки неспоріднених одиниць пам'яті (можуть бути будь-якого розміру і можуть зберігати що завгодно) і вказують на кожен інше, як ви хочете. Так само скажемо, що ви робите USB-накопичувач. Тепер ви хочете, щоб файли зберігалися як будь-який масив або як список посилань? Я думаю, ви зрозуміли, на що я вказую :)

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