Dvostruko povezani popis: C++, Python (Code Primjer)

โšก Pametni saลพetak

Dvostruko povezana lista je linearna struktura podataka u kojoj svaki ฤvor pohranjuje podatke plus dva pokazivaฤa, jedan na prethodni ฤvor i jedan na sljedeฤ‡i ฤvor, tako da se prolaz moลพe uฤinkovito kretati i naprijed i natrag.

  • ๐Ÿงฉ Struktura ฤvora: Svaki ฤvor u dvostruko povezanoj listi sadrลพi podatkovno polje, pret pokazivaฤ na prethodni ฤvor i sljedeฤ‡i pokazivaฤ na sljedeฤ‡i ฤvor.
  • ๐Ÿ” Dvosmjerni prolaz: Dodatni prethodni pokazivaฤ omoguฤ‡uje algoritmima da hodaju glava-rep i rep-glava-rep, ลกto jednostruko povezana lista ne moลพe uฤiniti.
  • โž• Umetanje Operaticije: ฤŒvorovi se mogu dodati na poฤetku, na kraju, nakon ciljnog ฤvora ili prije ciljnog ฤvora u konstantnom ili linearnom vremenu.
  • โž– brisanje Operaticije: Uklanjanjem glave, repa ili podudarnog ฤvora aลพuriraju se i prethodni i sljedeฤ‡i pokazivaฤi susjednih ฤvorova i oslobaฤ‘a se osloboฤ‘ena memorija.
  • ๐Ÿ’ป C++ i Python Code: Potpune implementacije demonstriraju rutine za umetanje, brisanje, pretraลพivanje i pomicanje s izvrลกnim izlazom.
  • ๐Ÿ“Š Sloลพenost: Umetanje ili brisanje na poฤetku ili kraju niza koลกta O(1); pretraลพivanje u prosjeku koลกta O(n); ukupna sloลพenost prostora je O(n).
  • ๐Ÿญ Primjena: Deques, LRU predmemorije, povijest preglednika, stogovi za poniลกtavanje i ponavljanje te popisi za reprodukciju glazbe oslanjaju se na dvostruko povezane liste.

Dvostruko povezana lista

ล to je dvostruko povezana lista?

U dvostruko povezanoj listi, svaki ฤvor ima veze i na prethodni i na sljedeฤ‡i ฤvor. Svaki ฤvor sastoji se od tri elementa: jedan sadrลพi podatke, a druga dva su pokazivaฤi na sljedeฤ‡i i prethodni ฤvor. Ova dva pokazivaฤa pomaลพu u kretanju naprijed ili natrag od odreฤ‘enog ฤvora.

Evo osnovne strukture dvostruko povezane liste.

Struktura dvostruko povezane liste

Struktura dvostruko povezane liste

Svaka povezana lista ima poฤetni i krajnji ฤvor. Poฤetni ฤvor nema pret (prethodni pokazivaฤ) ฤvor, a repni ฤvor nema sljedeฤ‡i ฤvor.

Evo nekoliko vaลพnih pojmova za dvostruko povezane liste:

  • Prethodna: Svaki ฤvor je povezan sa svojim prethodnim ฤvorom. Koristi se kao pokazivaฤ ili poveznica.
  • Sljedeฤ‡i: Svaki ฤvor je povezan sa svojim sljedeฤ‡im ฤvorom. Koristi se kao pokazivaฤ ili poveznica.
  • Podaci: Ovo se koristi za pohranu podataka u ฤvoru. Podaci mogu sadrลพavati i druge Strukture podataka unutar njega. Na primjer, string, rjeฤnik, skup, hashmap i druge strukture mogu se pohraniti u podatkovno polje.

Evo osnovne strukture jednog ฤvora u dvostruko povezanoj listi:

Struktura ฤvora u dvostruko povezanoj listi

Struktura ฤvora u dvostruko povezanoj listi

Operacije dvostruko povezanog popisa

Operacije dvostruko povezane liste ukljuฤuju dodavanje, brisanje, umetanje i uklanjanje ฤvorova, kao i kretanje po listi od vrha prema dnu ili od dna prema vrhu.

Evo popisa operacija koje se mogu implementirati na dvostruko povezanoj listi:

  • Umetanje ispred
  • Umetanje na repu ili posljednjem ฤvoru
  • Umetanje nakon ฤvora
  • Umetanje prije ฤvora
  • Brisanje sprijeda
  • Brisanje iz repa
  • Pretraลพivanje i brisanje ฤvora
  • Traverza od glave do repa
  • Preฤ‘ite repom u glavu

Implementacija i pseudokod za svaku od ovih operacija slijede u nastavku.

Umetanje ispred dvostruko povezane liste

Umetanje ispred znaฤi stvaranje ฤvora u povezanoj listi i njegovo postavljanje na poฤetak liste.

Na primjer, postoji zadani ฤvor 15Potrebno ga je dodati kao glavni ฤvor.

Prilikom izvoฤ‘enja ove operacije primjenjuju se dva vaลพna uvjeta:

  1. Novi ฤvor postaje glavni ฤvor ako je dvostruko povezana lista prazna.
  2. Ako veฤ‡ postoji glavni ฤvor, prethodni glavni ฤvor zamjenjuje se novim ฤvorom.

Evo pseudokoda za ovu operaciju:

function insertAtFront(ListHead, value):
  newNode = Node()
  newNode.value = value
  ListHead.prev = newNode
  newNode.next = ListHead
  newNode.prev = NULL
  return ListHead

Umetanje u prednji ฤvor

Umetanje u prednji ฤvor

Umetanje na kraj dvostruko povezane liste

Umetanje na kraj znaฤi stvaranje ฤvora u povezanoj listi i njegovo postavljanje na rep.

Ovu operaciju izvode dvije metode:

  • Metoda 1: Poฤnite pregledavati od poฤetka dvostruko povezane liste sve do sljedeฤ‡i postaje null. Zatim poveลพite novi ฤvor s sljedeฤ‡i pokazivaฤ.
  • Metoda 2: Uzmite posljednji ฤvor dvostruko povezane liste. Zatim, sljedeฤ‡i Pokazivaฤ zadnjeg ฤvora pokazuje na novi ฤvor. Novi ฤvor postaje repni ฤvor.

Evo pseudokoda za umetanje na repnom ฤvoru:

function insertAtTail(ListHead, value):
  newNode = Node()
  newNode.value = value
  newNode.next = NULL
  while ListHead.next is not NULL:
    ListHead = ListHead.next
  newNode.prev = ListHead
  ListHead.next = newNode
  return ListHead

Umetanje na kraj povezanog popisa

Umetanje na kraj povezanog popisa

Umetanje nakon ฤvora

Razmotrite postojeฤ‡u dvostruko povezanu listu kao ลกto je sljedeฤ‡a:

Umetanje nakon ฤvora

Cilj je umetnuti zadani ฤvor koji ฤ‡e biti povezan nakon ฤvora s vrijednoลกฤ‡u 12.

Korak 1) Prijeฤ‘ite od poฤetka do zadnjeg ฤvora. Provjerite koji ฤvor ima vrijednost 12.

Korak 2) Stvorite novi ฤvor i dodijelite ga kao sljedeฤ‡i pokazivaฤ ฤvora 12, sljedeฤ‡i ฤvor novog ฤvora bit ฤ‡e 15.

Evo pseudokoda za umetanje ฤvora nakon ฤvora u dvostruko povezanoj listi:

function insertAfter(ListHead, searchItem, value):
  List = ListHead
  newNode = Node()
  newNode.value = value
  while List.value is not equal searchItem:
    List = List.next
  newNode.next = List.next
  newNode.prev = List
  List.next = newNode

Umetanje nakon ฤvora

Umetanje nakon ฤvora

Umetanje prije ฤvora

Ova operacija je sliฤna umetanju nakon ฤvora. Pretraลพuje se odreฤ‘ena vrijednost ฤvora, zatim se stvara novi ฤvor i umeฤ‡e prije traลพenog ฤvora.

Za umetanje odreฤ‘enog ฤvora 15 prije ฤvora 12, prati ove korake:

Korak 1) Preฤ‘ite povezanim popisom od glavnog ฤvora do repnog ฤvora.

Korak 2) Provjeri ima li sljedeฤ‡i pokazivaฤ trenutnog ฤvora vrijednost 12.

Korak 3) Umetnite novi ฤvor kao sljedeฤ‡i ฤvor trenutnog ฤvora.

Evo pseudokoda za umetanje ฤvora prije ฤvora u dvostruko povezanoj listi:

function insertBefore(ListHead, searchItem, value):
  List = ListHead
  newNode = Node()
  newNode.value = value
  while List.next.value is not equal searchItem:
    List = List.next
  newNode.next = List.next
  newNode.prev = List
  List.next = newNode

Umetanje ฤvora ispred ฤvora

Umetanje ฤvora ispred ฤvora

Izbriลกi zaglavlje dvostruko povezane liste

Glavni ฤvor u dvostruko povezanoj listi nema prethodnih ฤvorova. Dakle, sljedeฤ‡i Pokazivaฤ postaje novi glavni ฤvor kada se trenutni glavni ฤvor ukloni. Takoฤ‘er je potrebno osloboditi memoriju koju zauzima izbrisani ฤvor.

Evo koraka za brisanje glavnog ฤvora:

Korak 1) Dodijelite varijablu trenutnom glavnom ฤvoru.

Korak 2) Posjetite sljedeฤ‡i ฤvor trenutnog glavnog ฤvora i napravite pret pokazivaฤ NULL. Ovo odvaja drugi ฤvor od prvog ฤvora.

Korak 3) Oslobodite memoriju koju je zauzimao prethodni glavni ฤvor.

Evo pseudokoda za brisanje glave iz dvostruko povezane liste:

function deleteHead(ListHead):
  PrevHead = ListHead
  ListHead = ListHead.next
  ListHead.prev = NULL
  PrevHead.next = NULL
  free memory(PrevHead)
  return ListHead

Brisanje glavnog ฤvora

Brisanje glavnog ฤvora

Nakon bilo kakvog brisanja potrebno je osloboditi dodijeljenu memoriju. U suprotnom, memorija za izbrisani blok ostaje zauzeta tijekom cijelog izvoฤ‘enja programa i nijedna druga aplikacija ne moลพe koristiti taj segment memorije.

Izbriลกi rep dvostruko povezane liste

Ova operacija je sliฤna brisanju glave. Umjesto glave, uklanja se rep. Da bi se ฤvor identificirao kao rep, provjerite je li sljedeฤ‡i pokazivaฤ null. Nakon brisanja repa, memorija se mora osloboditi.

Ova operacija je takoฤ‘er poznata kao brisanje s leฤ‘a.

Evo koraka kako to uฤiniti:

Korak 1) Pomiฤite se do repnog ฤvora dvostruko povezane liste.

Korak 2) Dodijelite varijablu ili pokazivaฤ repnom ฤvoru.

Korak 3) Postavi sljedeฤ‡i pokazivaฤ na NULL i oslobodi memoriju repnog ฤvora.

Evo pseudokoda za brisanje repnog ฤvora:

function deleteTail(ListHead):
  head = ListHead
  while ListHead.next is not NULL:
    ListHead = ListHead.next
  Tail = ListHead
  ListHead.prev.next = NULL
  free memory(Tail)
  return head

Izbriลกite rep dvostruko povezanog

Pretraลพivanje i brisanje ฤvora s dvostruko povezane liste

Ova operacija traลพi odreฤ‘enu vrijednost ฤvora i briลกe taj ฤvor. Linearno pretraลพivanje je potrebno jer je povezani popis linearna struktura podataka. Nakon brisanja, memorija se mora osloboditi.

Evo koraka za pretraลพivanje i brisanje ฤvora u dvostruko povezanoj listi:

Korak 1) Prolazite kroz povezanu listu od poฤetka dok vrijednost ฤvora ne bude jednaka traลพenoj stavci.

Korak 2) Dodijeli varijablu brisanje ฤvora do odgovarajuฤ‡eg ฤvora.

Korak 3) Poveลพi prethodni ฤvor od brisanje ฤvora na sljedeฤ‡i ฤvor i postavi sljedeฤ‡i ฤvor pret pokazivaฤ na prethodni ฤvor.

Korak 4) Oslobodite sjeฤ‡anje na brisanje ฤvora.

Evo pseudokoda za pretraลพivanje i brisanje ฤvora s povezane liste:

function searchAndDelete(ListHead, searchItem):
  head = ListHead
  while head.value not equals searchItem:
    head = head.next
  deleteNode = head
  head.prev.next = head.next
  if head.next is not NULL:
    head.next.prev = head.prev
  free memory(deleteNode)
  return ListHead

Pretraลพivanje i brisanje OperaANJE

Operacija pretraลพivanja i brisanja

Prolazak kroz dvostruko povezanu listu od naprijed

Prijelaz od glavnog ฤvora iterira preko sljedeฤ‡eg ฤvora dok se ne pronaฤ‘e NULL. Tijekom prelaska kroz svaki ฤvor, vrijednost se moลพe ispisati. Evo koraka za prelazak u smjeru naprijed:

Korak 1) Dodijelite pokazivaฤ ili varijablu trenutnom glavnom ฤvoru.

Korak 2) Iteriraj do sljedeฤ‡eg ฤvora glave dok ne dobijeลก NULL.

Korak 3) Ispiลกite podatke o ฤvorovima u svakoj iteraciji.

Korak 4) Vratite glavni ฤvor.

Evo pseudokoda za obilazak dvostruko povezane liste s poฤetka:

function traverseFromFront(ListHead):
  head = ListHead
  while head not equals NULL:
    print head.data
    head = head.next
  return ListHead

Povratak nije obavezan. Meฤ‘utim, vraฤ‡anje glavnog ฤvora nakon operacija je dobra praksa.

Prolazak kroz dvostruko povezanu listu od unatrag

Ova operacija je inverzna od kretanja sprijeda. Pristup je isti s jednom malom razlikom: prvo doฤ‘ite do krajnjeg ฤvora, a zatim hodajte unatrag do vrha koristeฤ‡i pret pokazivaฤ.

Evo koraka za obilazak dvostruko povezane liste s leฤ‘a:

Korak 1) Kreฤ‡ite se dok se ne doฤ‘e do repnog ฤvora.

Korak 2) Od repnog ฤvora, preฤ‘ite pomoฤ‡u pret dok prethodni ฤvor ne postane NULL. pret Pokazivaฤ je null za glavni ฤvor.

Korak 3) U svakoj iteraciji, ispiลกite podatke o ฤvoru.

Evo pseudokoda za prelazak s leฤ‘a:

function traverseFromBack(ListHead):
  head = ListHead
  while head.next is not NULL:
    head = head.next
  tail = head
  while tail is not NULL:
    print tail.value
    tail = tail.prev
  return ListHead

Razlika izmeฤ‘u jednostruko i dvostruko povezane liste

Glavna razlika izmeฤ‘u jednostruko povezane liste i dvostruko povezane liste je broj veza koje svaki ฤvor sadrลพi.

Razlika izmeฤ‘u jednostruko i dvostruko povezanih popisa

Evo razlike izmeฤ‘u ฤvorova jednostruko povezane liste i dvostruko povezane liste:

PoljePojedinaฤno povezani popisDvostruko povezana lista
StrukturaPojedinaฤno povezani popis ima jedno podatkovno polje i jednu vezu na sljedeฤ‡i ฤvor.Dvostruko povezani popis ima jedno podatkovno polje i dvije veze. Jedan za prethodni ฤvor i drugi za sljedeฤ‡i ฤvor.
obuhvaฤ‡anjeMoลพe iฤ‡i samo od glave do repa.Moลพe se kretati i naprijed i natrag.
memorijaZauzima manje memorije.Zauzima viลกe memorije od jednostruko povezane liste.
PristupaฤnostJednostruko povezane liste su manje uฤinkovite jer koriste samo jednu vezu do sljedeฤ‡eg ฤvora. Ne postoji veza do prethodnog ฤvora.Dvostruko povezane liste su uฤinkovitije od jednostruko povezanih lista za dvosmjerni pristup.

Dvostruko povezani popis u C++

Ispod je potpuni C++ Implementacija dvostruko povezane liste s operacijama umetanja, brisanja, pretraลพivanja i pomicanja.

#include<iostream>
using namespace std;
struct node{
  int data;
  struct node *next;
  struct node *prev;
};
void insertFront(node* &listHead, int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  if(listHead != NULL){
    listHead->prev = newNode;
    newNode->next = listHead;
  }
  listHead = newNode;
  cout<<"Added "<<value<<" at the front"<<endl;
}
void insertEnd(node* &listHead, int value){
  if(listHead == NULL){
    insertFront(listHead, value);
    return;
  }
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  node *head = listHead;
  while(head->next != NULL){
    head = head->next;
  }
  head->next = newNode;
  newNode->prev = head;
  cout<<"Added "<<value<<" at the end"<<endl;
}
void insertAfter(node* &listHead, int searchValue, int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  node *head = listHead;
  while(head->next != NULL && head->data != searchValue){
    head = head->next;
  }
  newNode->next = head->next;
  head->next = newNode;
  newNode->prev = head;
  if(newNode->next != NULL){
    newNode->next->prev = newNode;
  }
  cout<<"Inserted "<<value<<" after node "<<searchValue<<endl;
}
void insertBefore(node* &listHead, int searchValue, int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  node *head = listHead;
  while(head->next != NULL && head->next->data != searchValue){
    head = head->next;
  }
  newNode->next = head->next;
  head->next = newNode;
  newNode->prev = head;
  if(newNode->next != NULL){
    newNode->next->prev = newNode;
  }
  cout<<"Inserted "<<value<<" before node "<<searchValue<<endl;
}
void traverseFromFront(node *listHead){
  node* head = listHead;
  cout<<"Traversal from head:\t";
  while(head != NULL){
    cout<<head->data<<"\t";
    head = head->next;
  }
  cout<<endl;
}
void traverseFromEnd(node *listHead){
  node* head = listHead;
  cout<<"Traversal from tail:\t";
  while(head->next != NULL){
    head = head->next;
  }
  node *tail = head;
  while(tail != NULL){
    cout<<tail->data<<"\t";
    tail = tail->prev;
  }
  cout<<endl;
}
void searchAndDelete(node **listHead, int searchItem){
  node* head = (*listHead);
  while(head != NULL && head->data != searchItem){
    head = head->next;
  }
  if(*listHead == NULL || head == NULL) return;
  if((*listHead)->data == head->data){
    *listHead = head->next;
  }
  if(head->next != NULL){
    head->next->prev = head->prev;
  }
  if(head->prev != NULL){
    head->prev->next = head->next;
  }
  free(head);
  cout<<"Deleted Node\t"<<searchItem<<endl;
}
int main(){
  node *head = NULL;
  insertFront(head, 5);
  insertFront(head, 6);
  insertFront(head, 7);
  insertEnd(head, 9);
  insertEnd(head, 10);
  insertAfter(head, 5, 11);
  insertBefore(head, 5, 20);
  traverseFromFront(head);
  traverseFromEnd(head);
  searchAndDelete(&head, 7);
  traverseFromFront(head);
  traverseFromEnd(head);
}

Izlaz

Added 5 at the front
Added 6 at the front
Added 7 at the front
Added 9 at the end
Added 10 at the end
Inserted 11 after node 5
Inserted 20 before node 5
Traversal from head:    7  6  20  5  11  9  10
Traversal from tail:    10  9  11  5  20  6  7
Deleted Node    7
Traversal from head:    6  20  5  11  9  10
Traversal from tail:    10  9  11  5  20  6

Dvostruko povezani popis u Python

Ispod je potpuni Python implementacija dvostruko povezane liste koriลกtenjem klasa za ฤvorove i same liste.

class Node:
  def __init__(self, data=None, prev=None, next=None):
    self.data = data
    self.next = next
    self.prev = prev
class DoublyLinkedList:
  def __init__(self):
    self.head = None
  def insertFront(self, val):
    newNode = Node(data=val)
    newNode.next = self.head
    if self.head is not None:
      self.head.prev = newNode
    self.head = newNode
    print("Added {} at the front".format(val))
  def insertEnd(self, val):
    newNode = Node(data=val)
    if self.head is None:
      self.head = newNode
      print("Added {} at the end".format(val))
      return
    temp = self.head
    while temp.next is not None:
      temp = temp.next
    temp.next = newNode
    newNode.prev = temp
    print("Added {} at the end".format(val))
  def traverseFromFront(self):
    temp = self.head
    print("Traversing from head:\t", end="")
    while temp is not None:
      print("{}\t".format(temp.data), end="")
      temp = temp.next
    print()
  def traverseFromEnd(self):
    temp = self.head
    print("Traversing from tail:\t", end="")
    while temp.next is not None:
      temp = temp.next
    tail = temp
    while tail is not None:
      print("{}\t".format(tail.data), end="")
      tail = tail.prev
    print()
  def insertAfter(self, searchItem, value):
    newNode = Node(data=value)
    temp = self.head
    while temp.next is not None and temp.data != searchItem:
      temp = temp.next
    newNode.next = temp.next
    temp.next = newNode
    newNode.prev = temp
    if newNode.next is not None:
      newNode.next.prev = newNode
    print("Inserted {} after node {}".format(value, searchItem))
  def insertBefore(self, searchItem, value):
    newNode = Node(data=value)
    temp = self.head
    while temp.next is not None and temp.next.data != searchItem:
      temp = temp.next
    newNode.next = temp.next
    temp.next = newNode
    newNode.prev = temp
    if newNode.next is not None:
      newNode.next.prev = newNode
    print("Inserted {} before node {}".format(value, searchItem))
  def searchAndDelete(self, searchItem):
    temp = self.head
    while temp is not None and temp.data != searchItem:
      temp = temp.next
    if self.head is None or temp is None:
      return
    if self.head.data == temp.data:
      self.head = temp.next
    if temp.next is not None:
      temp.next.prev = temp.prev
    if temp.prev is not None:
      temp.prev.next = temp.next
    print("Deleted Node\t{}".format(searchItem))
doublyLinkedList = DoublyLinkedList()
doublyLinkedList.insertFront(5)
doublyLinkedList.insertFront(6)
doublyLinkedList.insertFront(7)
doublyLinkedList.insertEnd(9)
doublyLinkedList.insertEnd(10)
doublyLinkedList.insertAfter(5, 11)
doublyLinkedList.insertBefore(5, 20)
doublyLinkedList.traverseFromFront()
doublyLinkedList.traverseFromEnd()
doublyLinkedList.searchAndDelete(7)
doublyLinkedList.traverseFromFront()
doublyLinkedList.traverseFromEnd()

Izlaz

Added 5 at the front
Added 6 at the front
Added 7 at the front
Added 9 at the end
Added 10 at the end
Inserted 11 after node 5
Inserted 20 before node 5
Traversing from head:   7  6  20  5  11  9  10
Traversing from tail:   10  9  11  5  20  6  7
Deleted Node    7
Traversing from head:   6  20  5  11  9  10
Traversing from tail:   10  9  11  5  20  6

Sloลพenost dvostruko povezane liste

Vremenska sloลพenost se opฤ‡enito dijeli na tri vrste: najbolji sluฤaj, prosjeฤni sluฤaj i najgori sluฤaj.

Vremenska sloลพenost u najboljem sluฤaju za dvostruko povezani popis:

  1. Umetanje na poฤetku ili kraju liste koลกta O(1) jer nije potreban prolaz unutar povezane liste. Pokazivaฤi na poฤetku i kraju liste daju izravan pristup poฤetnim i krajnjim ฤvorovima.
  2. Brisanje na poฤetku ili kraju skupa koลกta O(1).
  3. Pretraลพivanje ฤvora koลกta O(1) kada je ciljni ฤvor glavni ฤvor.

Vremenska sloลพenost u prosjeฤnom sluฤaju za dvostruko povezani popis:

  1. Umetanje na poฤetku ili kraju koลกta O(1).
  2. Brisanje na poฤetku ili kraju skupa koลกta O(1).
  3. Pretraลพivanje ฤvora koลกta O(n), jer se cilj moลพe nalaziti bilo gdje na popisu. Ovdje, n je ukupan broj ฤvorova.

Vremenska sloลพenost dvostruko povezane liste u najgorem sluฤaju ista je kao i u prosjeฤnom sluฤaju.

Memorijska sloลพenost dvostruko povezanog popisa

Sloลพenost memorije je O(n), gdje je n je ukupan broj ฤvorova. Tijekom implementacije povezane liste, memorija se mora osloboditi. Inaฤe, veฤ‡e povezane liste uzrokuju curenje memorije.

Primjene dvostruko povezane liste

Dvostruko povezane liste pokreฤ‡u nekoliko stvarnih struktura podataka jer dvosmjerni prolaz pojednostavljuje mnoge uobiฤajene operacije.

  • LRU predmemorija: Najmanje koriลกtene predmemorije koriste dvostruko povezanu listu s hash mapom za O(1) premjeลกtanje na poฤetak i deloลพiranje.
  • Povijest preglednika: Navigacija naprijed i natrag omoguฤ‡uje kretanje po povezanom popisu u oba smjera.
  • Poniลกti i ponovi nizove: Urednici i IDE-ovi track verzija dokumenata s pokazivaฤima na prethodno i sljedeฤ‡e.
  • Deque: DoubleRedovi s krajevima se guraju i otvaraju s oba kraja u vremenu O(1).
  • Glazbene liste za reprodukciju: Prethodno i sljedeฤ‡e tracGumbi k oslanjaju se na pokazivaฤe naprijed i natrag.

Pitanja i odgovori

Dvostruko povezane liste vraฤ‡aju LRU predmemorije koriลกtene u batch cjevovodima dubokog uฤenja i front-endovima za pohranu vektora, omoguฤ‡ujuฤ‡i AI sustavima da premjeste nedavno pristupljene tenzore na poฤetak u O(1) vremenu za brzu ponovnu upotrebu.

Da. GitHub Copilot i GPT mogu generirati potpunu dvostruko povezanu listu u C-u, C++, Java, Python, ili Rust, ukljuฤujuฤ‡i metode umetanja, brisanja, pretraลพivanja i obrnutog prolaska, plus jediniฤne testove.

Jednostruko povezana lista ima jedan pokazivaฤ na sljedeฤ‡i ฤvor i kreฤ‡e se u jednom smjeru. Dvostruko povezana lista ima i pokazivaฤe na prethodni i sljedeฤ‡i ฤvor te se kreฤ‡e naprijed i natrag, ali koristi viลกe memorije.

Uobiฤajene primjene ukljuฤuju LRU predmemorije, povijest pregledavanja naprijed i natrag, nizove za poniลกtavanje i ponavljanje u ureฤ‘ivaฤima, implementacije deque-a, navigaciju popisima za reprodukciju i rasporeฤ‘ivanje niti u operativnim sustavima.

Umetanje ili brisanje na poฤetku ili kraju je O(1). Pretraลพivanje ili umetanje ili brisanje na proizvoljnoj poziciji je O(n). Prostorna sloลพenost je O(n) jer svaki ฤvor pohranjuje dodatni pokazivaฤ na prethodno.

Dvostruko povezane liste nude O(1) umetanje i brisanje na oba kraja i dinamiฤku alokaciju memorije. Nizovi nude O(1) sluฤajni pristup i bolju lokalnost predmemorije. Odaberite na temelju radnog optereฤ‡enja.

Zamijenite pokazivaฤe na prethodni i sljedeฤ‡i ฤvor svakog ฤvora tijekom jednog hoda po listi. Kada petlja zavrลกi, aลพurirajte pokazivaฤ na poฤetak na ono ลกto je prije bio pokazivaฤ na rep. Operacija se izvrลกava u vremenu O(n).

Da. Kruลพna dvostruko povezana lista povezuje sljedeฤ‡i pokazivaฤ repa s glavom i prethodni pokazivaฤ glave s repom. Ova se struktura koristi u kruลพnom rasporeฤ‘ivanju i prstenovima meฤ‘uspremnika.

Saลพmite ovu objavu uz: