ArrayList vs. LinkedList vs. Vector

Пасадзіць працу ў інжынерна-тэхнічную ролю значна прасцей, чым думаюць людзі. Але ў некаторых выпадках большасць маіх людзей з шматгадовым досведам працы ў гэтай экспертызе правалілі кандыдатуру. "У чым праблема?" Пытанне накачваецца ў маёй галаве.

Я атрымліваў асалоду ад свайго часу, калі роля інжынерыі праграмнага забеспячэння яшчэ больш люблю тое, што я раблю са сваім кодам за апошнія 6 гадоў. За гэты час у мяне былі дзіўныя ўражанні, апытваючы многіх кандыдатаў праграмнага забеспячэння. У кожным працэсе інтэрв'ю я не толькі чакаю, што кандыдаты будуць добра абгрунтаваны ў такіх тэмах, як добрыя прынцыпы распрацоўкі праграмнага забеспячэння, архітэктура маштабаванага кода і тэставанне, але і свае веды ў галіне асноўных структуры дадзеных і алгарытму праграмнай інжынерыі. Мне было так сумна, калі многія кандыдаты не разумелі асноўнага.

Акрамя таго, што за кароткі прамежак часу можна даведацца новыя рамкі, інструменты і нават мовы праграмавання, добрае разуменне структуры дадзеных - адно з ключавых ведаў, якое вы павінны мець, калі хочаце працягнуць кар'еру праграмнага інжынера.

Структура дадзеных - гэта асаблівы спосаб захоўвання і арганізацыі інфармацыі ў кампутары, каб яе можна было знайсці і выкарыстоўваць найбольш эфектыўна. Розныя віды структур дадзеных прызначаны для розных відаў прыкладанняў, а некаторыя вузкаспецыялізуюцца на канкрэтных задачах. - Вікіпедыя

Чаму структура дадзеных становіцца адным з важных ведаў? Структура дадзеных і алгарытм забяспечваюць набор метадаў для эфектыўнай работы з дадзенымі. Калі кандыдаты не ведаюць пра структуру і алгарытм дадзеных, яны не змогуць напісаць эфектыўны код для апрацоўкі дадзеных. Ведаючы, як структура дадзеных захоўвае свае дадзеныя, як яны працуюць і калі выкарыстоўваць з загадзя вызначаным наборам метадаў, палепшыць час, неабходны для вырашэння праблемы. Адно з пытанняў, на якое кандыдаты часта не адказваюць, - гэта

Каго з іх лепш, ArrayList, LinkedList ці Vector?

Спіс

Перш чым адказаць на пытанне, добра ведаць, што такое спіс. Спіс - гэта абстрактны тып дадзеных (ADT), які захоўвае свае элементы ў паслядоўнасці і дазваляе нам дадаваць, выдаляць і атрымліваць доступ да яго элементаў з дапамогай індэкса. Масіў - гэта адна з структур дадзеных, якая рэалізуе спіс ADT. У масіве мы можам дадаваць, выдаляць і атрымаць элемент, выкарыстоўваючы індэкс. ArrayList, LinkedList і Vector - яшчэ адзін прыклад структур дадзеных, якія рэалізуюць спіс ADT. Калі ArrayList, LinkedList і Vector маюць дынамічны памер (змяняць памер), у той час як статычны памер мае статычны памер. Калі масіў аб'яўляецца даўжынёй 7, то ён будзе мець даўжыню 7 да канца сваёй вобласці. У той час як ArrayList, LinkedList і Vector могуць захоўваць дадзеныя як мага больш, дзе ліміт складае агульную колькасць даступнай памяці.

Рамка калекцыі Java. Крыніца: Вікіпедыя

У Java Collection Framework спіс ADT рэалізуецца як інтэрфейс пад назвай List, а ArrayList, LinkedList & Vector - канкрэтны клас, які рэалізуе інтэрфейс List. Паколькі гэтыя канкрэтныя класы рэалізуюць адзін і той жа інтэрфейс, гэтыя класы павінны мець аднолькавую функцыянальнасць, таму што для ўсіх неабразіўных класаў, якія рэалізуюць інтэрфейс, патрабуецца рэалізаваць усе абстрактныя метады, заяўленыя ў інтэрфейсе.

Як захоўваюцца дадзеныя

Прынцыповае адрозненне трох вышэйпералічаных структур дадзеных у тым, як яны захоўваюць свае дадзеныя, што выклікае розную прадукцыйнасць для розных аперацый. У Java (і таксама выкарыстоўваецца ў Kotlin) ArrayList і Vector выкарыстоўваюць масіў для захоўвання сваіх элементаў, у той час як LinkedList захоўвае яго элементы ў падвойным спісе.

У інфарматыцы падвойны спіс - гэта звязаная структура дадзеных, якая складаецца з набору паслядоўна звязаных запісаў, званых вузламі. Кожны вузел змяшчае два палі, званыя спасылкамі, якія спасылаюцца на папярэдні і наступны вузел у паслядоўнасці вузлоў. - Вікіпедыя
ArrayList (уверсе) супраць LinkedList (унізе). Крыніца https://dzone.com/storage/temp/895349-arraylist-linkedlistt.png

У LinkedList першы вузел можа ведаць другі вузел. Другі вузел можа ведаць першы і трэці вузлы. Трэці вузел можа ведаць другі і чацвёрты вузлы. І гэтак далей, вузел можа ведаць папярэдні вузел і наступны. Спецыяльна для першага вузла ў LinkedList не будзе папярэдняга вузла, а для апошняга вузла ў LinkedList не будзе наступнага.

Вось фрагмент кода, як ArrayList захоўвае свае элементы ў масіве.

/ **
 * Буфер масіва, у які ўваходзяць элементы ArrayList
 * захоўваецца. Ёмістасць ArrayList - гэта даўжыня
 * буфер масіва. Любы пусты ArrayList з elementData ==
 * DEFAULTCAPACITY_EMPTY_ELEMENTDATA будзе пашыраны да
 * DEFAULT_CAPACITY пры даданні першага элемента.
 * /
пераходны аб'ект [] elementData; // непрыватная для спрашчэння укладзенай
                                // Доступ да класа

І вось, як Vector захоўвае свае элементы таксама ў масіве.

/ **
 * Буфер масіва, у які ўваходзяць кампаненты вектара
 * захоўваецца. Ёмістасць вектара - гэта даўжыня гэтага масіва
 * буфер, і, па меншай меры, дастаткова вялікі, каб утрымліваць усе вектары
 * элементы.
 *
 * 

Любыя элементы масіва, якія ідуць за апошнім элементам вектара  * з'яўляюцца нулявымі.  *  * @ серыял  * / абаронены аб'ект [] elementData;

У згаданым фрагменце кода мы бачым, што і ArrayList і Vector захоўваюць свае элементы ў зменнай, названай elementDatawith Object [], як яго тып. Чаму аб'ект []? Object з'яўляецца суперкласам усіх класаў на Java. Вызначыўшы elementData як Object [], тады elementData можа захоўваць розныя тыпы элементаў, гэта можа быць String, Integer, Double, Float або карыстацкі клас, як Pair, TextView і гэтак далей.

Чаму ArrayList і Vector выкарыстоўваюць Array для захоўвання сваіх дадзеных? Як ужо згадвалася раней, хоць ArrayList і Vector выкарыстоўваюць масівы для захоўвання сваіх дадзеных, ArrayList і Vector маюць магчымасць мець дынамічныя памеры (змяняць змен). Калі масіў, выкарыстаны ў ArrayList і Vector, запоўнены, яны могуць "расці", каб павялічыць яго магутнасць. ArrayList і Vector павялічваюць свой патэнцыял, стварыўшы новы масіў памерам больш, чым папярэдні памер, а потым капіюе ўсе элементы са старога масіва ў новы масіў з дапамогай каманды Arrays.copyOf. Вось фрагмент кода праграмы ў ArrayList для павелічэння яе магутнасці (крыніца: ArrayList.java).

/ **
  * Павялічвае здольнасць да таго, каб ён мог утрымліваць як мінімум
  * колькасць элементаў, зададзеных аргументам мінімальнай магутнасці.
  *
  * @param minCapacity патрэбная мінімальная ёмістасць
  * /
  прыватная несапраўдная расці (int minCapacity) {
      // Код празмернага перапаўнення
      int oldCapacity = elementData.length;
      int newCapacity = oldCapacity + (oldCapacity >> 1);
      калі (newCapacity - minCapacity <0)
          newCapacity = minCapacity;
      калі (newCapacity - MAX_ARRAY_SIZE> 0)
          newCapacity = вялізная магутнасць (minCapacity);
      // minCapacity звычайна набліжаецца да памеру, таму гэта выйгрыш:
      elementData = Arrays.copyOf (elementData, newCapacity);
  }

А вось як Vector павялічвае сваю магутнасць (крыніца: Vector.java)

прыватнае несапраўднае расці (int minCapacity) {
    // Код празмернага перапаўнення
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + ((capacIncrement> 0)?
                                     нарошчванне магутнасці: oldCapacity);
    калі (newCapacity - minCapacity <0)
        newCapacity = minCapacity;
    калі (newCapacity - MAX_ARRAY_SIZE> 0)
        newCapacity = вялізная магутнасць (minCapacity);
    elementData = Arrays.copyOf (elementData, newCapacity);
}

Рэалізацыя вектараў амаль ідэнтычная ArrayList, і адрозненне заключаецца ў тым, што ўсе аперацыі ў Vector сінхранізуюцца, што робіць любы метад, які датычыцца змесціва вектара, бяспечным для тэмы.

І які з іх лепш, ArrayList, LinkedList ці Vector? Каб адказаць на гэтае пытанне, можна параўнаць прадукцыйнасць для звычайных аперацый у ArrayList і LinkedList. Паколькі рэалізацыя ArrayList і Vector амаль аднолькавая, іх прадукцыйнасць таксама будзе амаль аднолькавай.

Параўнанне прадукцыйнасці паміж ArrayList і LinkedList

З прыведзенай табліцы мы бачым, што для ўсіх аперацый няма срэбнай кулі. ArrayList пераўзыходзіць LinkedList пры выпадковым доступе (атрымаць). ArrayList лепш, чым LinkedList, таму што ArrayList захоўвае свае элементы ў масіве, у той час як LinkedList захоўвае яго элементы ў звязаным вузле. Напрыклад, каб атрымаць 5-ы элемент, ArrayList і Vector могуць атрымаць непасрэдна яго элемент, выкарыстоўваючы індэкс, паколькі ArrayList і Vector па сутнасці гэта масіў, у той час як LinkedList павінен ітэраваць, каб даведацца пяты элемент, таму што ў LinkedList мы можам ведаць толькі першы і толькі апошні элемент.

Для insertFirst і deleteFirst LinkedList пераўзыходзіць ArrayList. ArrayList патрабуе вялікіх намаганняў, каб дадаць элемент у самым пачатку (першы індэкс) або выдаліць першы элемент, таму што ArrayList павінен перакласці наступныя элементы пасля дадання або выдалення. У той час як LinkedList трэба толькі замяніць / ўсталяваць свае паказальнікі. Што тычыцца іншых функцый, і ArrayList і LinkedList маюць аднолькавую прадукцыйнасць.

І які з іх лепш, ArrayList, LinkedList ці Vector? Залежыць ад вашых патрэбаў. Калі вы выкарыстоўваеце выпадковы доступ (атрымаць) часцей, то ArrayList і Vector - добры выбар. Выберыце "Вектар", калі вам патрэбна калекцыя з бяспечнай тэмай. Але калі вы часта робіце дапаўненні і выдаленні на першай пазіцыі (індэксе), LinkedList - лепшы выбар.

Існуе яшчэ адзін ADT, які звычайна выкарыстоўваецца пры распрацоўцы прыкладанняў, такіх як Set, Map і PriorityQueue. Каб ведаць, як яны захоўваюць свае дадзеныя, як яны працуюць і калі карыстацца, сочыце за маім Medium.