For faster navigation, this Iframe is preloading the Wikiwand page for Двойносвързан списък.

Двойносвързан списък

Тази статия се нуждае от подобрение. Необходимо е: проверка на превода.Ако желаете да помогнете на Уикипедия, използвайте опцията редактиране в горното меню над статията, за да нанесете нужните корекции.

В компютърните науки двойно свързаният списък е свързана структура от данни, състояща се от множество последователно свързани елементи. Всеки един елемент съдържа две полета, наречени връзки, които са референции (указатели) към предишния и следващия елемент в поредицата от елементи. Връзките на началните и крайните елементи в двойно свързания списък имат по един специален вид разклонение, служещо за прекратяване обхождането на списъка. Този специален вид разклонение обичайно е празен елемент (sentinel node) или null. Ако списъкът има само един празен елемент, то той е кръгообразно свързан чрез него. Двойно свързаният списък може да бъде представен и като два отделни единично свързани списъка, съставящи се от едни и същи елементи, но в противоположен ред.

Двойно свързан списък, чиито елементи съдържат три полета: елемент със стойност от целочислен тип (integer), връзката към следващия елемент (node) и такава към предишния

Това, което позволява обхождането на списъка в двете посоки, са двете връзки на всеки елемент. Въпреки че добавянето и премахването на елемент от двойно свързания списък изисква промяната на повече връзки, отколкото същата операция в единично свързания, операциите са по-опростени и потенциално по-ефикасни (за елементите, различни от крайните), защото по време на обхождане няма нужда да се взима под внимание връзката към предишното разклонение и няма нужда да се обхожда списъкът, за да се открие връзката, която трябва да се промени.

Тази концепция е и в основата на техниката за запаметяване в мнемоничната свързваща система (наричана още „свързващ метод“).

Номенклатура и имплементация

[редактиране | редактиране на кода]

Първият и последният елемент на двойно свързания списък, наричани съответно „head“ (глава) и „tail“ (опашка), могат да бъдат достигнати незабавно (т.е. без обхождане на списъка). Те позволяват обхождането на списъка от началото или края – например обхождане на списъка от началото към края или от края към началото за намиране на елемент с конкретна стойност. След като се намери конкретен елемент с дадена стойност, той може да се използва като начало за ново обхождане на списъка в двете посоки – към началото на списъка или към неговия край.

Полетата, представляващи връзките към съседните елементи в двойно свързания списък, често се наричат next и previous или forward и backward, съответно предходен и следващ. Указателите, които държат съответните полета, най-често са представени катоpointer, но могат също така да бъдат и адресни отклонения или индекси в масив, в който съществуват елементите, към които се сочи.

Представени са следните основни алгоритми, написани на Ada:

Отворен свързан списък

[редактиране | редактиране на кода]
record DoublyLinkedNode {
    prev // A reference to the previous node
    next // A reference to the next node
    data // Data or a reference to data
}
record DoublyLinkedList {
     DoublyLinkedNode firstNode // points to first node of list
     DoublyLinkedNode lastNode // points to last node of list
}

Обхождането на двойно свързания списък може да се направи и в двете посоки. Посоката на обхождане може да бъде променяна многократно. Обхождането често се среща като итерация, но използването на тази терминология е неподходящо, тъй като итерация има добре дефинирана семантика (например в математиката), която не е аналог на обхождане.

Обхождане отпред назад с отправна точка първи елемент:

node := list.firstNode
 while node ≠ null
     <do something with node.data>
     node := node.next

Обхождане отзад напред с отправна точка последен елемент:

node := list.lastNode
 while node ≠ null
     <do something with node.data>
     node := node.prev

Вмъкване на елемент

[редактиране | редактиране на кода]

За вмъкването на елемент преди или след конкретен елемент се използват следните симетрични функции:

function insertAfter(List list, Node node, Node newNode)
     newNode.prev := node
     newNode.next := node.next
     if node.next == null
         list.lastNode := newNode
     else
         node.next.prev := newNode
     node.next := newNode
function insertBefore(List list, Node node, Node newNode)
     newNode.prev := node.prev
     newNode.next := node
     if node.prev == null
         list.firstNode := newNode
     else
         node.prev.next := newNode
     node.prev := newNode

За вмъкването на елемент в началото на празен списък се използва функцията:

function insertBeginning(List list, Node newNode)
     if list.firstNode == null
         list.firstNode := newNode
         list.lastNode := newNode
         newNode.prev := null
         newNode.next := null
     else
         insertBefore(list, list.firstNode, newNode)

За вмъкването на елемент в края на списъка се използва симетричната функция:

function insertEnd(List list, Node newNode)
     if list.lastNode == null
         insertBeginning(list, newNode)
     else
         insertAfter(list, list.lastNode, newNode)

Премахване на елемент

[редактиране | редактиране на кода]

Премахванто на елемент (node) е по-лесно от вмъкването му, но изисква особен подход, ако елементът за премахване е първият (firstNode) или последният (lastnNode):

function remove(List list, Node node)
   if node.prev == null
       list.firstNode := node.next
   else
       node.prev.next := node.next
   if node.next == null
       list.lastNode := node.prev
   else
       node.next.prev := node.prev

Нежелан ефект от предходния пример е довеждането до стойност null на firstNode и lastNode. Ако се вгледаме по-внимателно, можем да забележим, че няма нужда от отделни функции removeBefore и removeAfter, защото в двойно свързаният списък може да се използва remove(node.prev) или remove(node.next). Това също така гарантира, че елементът, който се отстранява съществува. Ако елементът не съществува в списъка, ще възникне грешка (Exception), която ще трябва да се обработи.

Кръгов двойно свързани списък

[редактиране | редактиране на кода]

Ако се приеме, че someNode е елемент в списък (който не е празен), следващият пример ще обходи списъка, използвайки someNode като отправна точка, която може да бъде който и да е елемент от списъка.

Обхождане отпред назад с отправна точка първи елемент:

node := someNode
 do
     do something with node.value
     node := node.next
 while node ≠ someNode

Обхождане отзад напред с отправна точка последен елемент:

node := someNode
 do
     do something with node.value
     node := node.prev
 while node ≠ someNode

Обърнете внимание, че проверката за прекратяване на обхождането се извършва, след като той се е изпълнил поне веднъж. Това е нужно в случаите, когато списъкът съдържа единствено елемента someNode, който е нашата отправна и крайна точка.

Вмъкване на елемент

[редактиране | редактиране на кода]

Вмъкването на елемент след даден елемент в кръговия двойно свързан списък става чрез следната функция:

function insertAfter(Node node, Node newNode)
     newNode.next := node.next
     newNode.prev := node
     node.next.prev := newNode
     node.next := newNode

За да вмъкнем елемент преди някой друг (insertBefore), можем отново да използваме функцията insertAfter(node.prev, newNode).

Вмъкване на елемент в празен списък изисква използването на по-сложна функция:

function insertEnd(List list, Node node)
     if list.lastNode == null
         node.prev := node
         node.next := node
     else
         insertAfter(list.lastNode, node)
     list.lastNode := node

За да вмъкнем елемент в началото, можем да използваме insertAfter(list.lastNode, node).

Премахването на елемент (node) става чрез следната функция, която се съобразява с това, че елементите в списъка намаляват:

function remove(List list, Node node)
     if node.next == node
         list.lastNode := null
     else
         node.next.prev := node.prev
         node.prev.next := node.next
         if node == list.lastNode
             list.lastNode := node.prev;
     destroy node

Свързаните списъци са подходящи, когато не се знае колко на брой елементи ще има в колекцията и се цели бързина при вмъкване или премахване на елемент. Тези операции са с константна сложност, тъй като засегнатите елементи от тях са само съседните и по-точно техните връзки.

За сметка на това свързаните списъци не са подходящи, когато има нужда от чест достъп до произволни елементи от списъка. В случая това е бавна операция в сравнение с повечето колекции, тъй като няма индексация на елементите и за да се намери някой конкретен, трябва да се обходи списъкът, докато не се открие търсеният елемент.

  • Единично свързан списък

Read Sort List

  Тази страница частично или изцяло представлява превод на страницата Doubly_linked_list в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите. ​

ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни.​

{{bottomLinkPreText}} {{bottomLinkText}}
Двойносвързан списък
Listen to this article

This browser is not supported by Wikiwand :(
Wikiwand requires a browser with modern capabilities in order to provide you with the best reading experience.
Please download and use one of the following browsers:

This article was just edited, click to reload
This article has been deleted on Wikipedia (Why?)

Back to homepage

Please click Add in the dialog above
Please click Allow in the top-left corner,
then click Install Now in the dialog
Please click Open in the download dialog,
then click Install
Please click the "Downloads" icon in the Safari toolbar, open the first download in the list,
then click Install
{{::$root.activation.text}}

Install Wikiwand

Install on Chrome Install on Firefox
Don't forget to rate us

Tell your friends about Wikiwand!

Gmail Facebook Twitter Link

Enjoying Wikiwand?

Tell your friends and spread the love:
Share on Gmail Share on Facebook Share on Twitter Share on Buffer

Our magic isn't perfect

You can help our automatic cover photo selection by reporting an unsuitable photo.

This photo is visually disturbing This photo is not a good choice

Thank you for helping!


Your input will affect cover photo selection, along with input from other users.

X

Get ready for Wikiwand 2.0 🎉! the new version arrives on September 1st! Don't want to wait?