Enkelt länkad lista i datastrukturer
Vad är en enstaka länkad lista?
Singly Linked List är en linjär och enkelriktad datastruktur, där data sparas på noderna och varje nod är ansluten via en länk till nästa nod. Varje nod innehåller ett datafält och en länk till nästa nod. Enkelt länkade listor kan passeras i endast en riktning, medan dubbellänkade listor kan passeras i båda riktningarna.
Här är en nodstruktur för en Singly Linked List:
Varför använda länkad lista över array?
Det finns flera fall då det är bättre att använda den länkade listan istället för array. Här är några scenarier:
- Okänt antal element: När du inte vet hur många element du behöver lagra under programmets körning, kan du använda den länkade listan. Minnet allokeras dynamiskt när du lägger till element i de länkade listorna.
- Slumpmässig tillgång: I ett scenario, där du inte behöver använda slumpmässig åtkomst från elementen, kan du använda den länkade listan.
- Insättning i mitten: Insättning i mitten av en array är en komplex uppgift. För du måste trycka andra element åt höger. Men en länkad lista låter dig lägga till ett element till vilken position du vill.
Operationer av Singly Linked List
Singly Linked List är bra för att dynamiskt allokera minne. Den tillhandahåller alla grundläggande funktioner för den länkade listan, dvs infogning, radering, sökning, uppdatering, sammanfogning av två länkade listor, korsning, etc.
Här kommer vi att diskutera följande funktion för den länkade listan:
- Insättning vid huvudet
- Insättning i svansen
- Infogar efter en nod
- Infogar före en nod
- Ta bort huvudnoden
- Ta bort svansnoden
- Sök och ta bort en nod
- Gå igenom den länkade listan
Här är ett exempel på en länkad lista med fyra noder.
Infogning i spetsen för en Singly Linked List
Detta är en enkel operation. I allmänhet är det känt som att trycka på en enkellänkad lista. Du måste skapa en ny nod och placera denna högst upp i den länkade listan.
För att utföra denna operation måste vi följa två viktiga villkor. Det är de
- Om listan är tom kommer den nyskapade noden att vara huvudnoden, och nästa nod på huvudet kommer att vara ”NULL”.
- Om listan inte är tom kommer den nya noden att vara huvudnoden, och nästa kommer att peka på den föregående huvudnoden.
Här är pseudokoden för att infoga en nod i spetsen av en länkad lista:
function insertAtHead( head, value ): newNode = Node(value) if head is NULL: head = newNode return head else: newNode.next = head return newNode
Infogning i slutet av en enkellänkad lista
Att infoga en nod i slutet av en länkad lista har vissa likheter med att infoga i huvudet. Allt du behöver göra är att gå till slutnoden eller svansnoden. Peka sedan "nästa" nod i slutnoden till den nyskapade noden. Om huvudnoden är noll kommer den nya noden att vara huvudnoden.
Här är stegen:
Steg 1) Traversera tills "nästa" nod för den aktuella noden blir noll.
Steg 2) Skapa en ny nod med det angivna värdet.
Steg 3) Tilldela den nya noden som nästa nod i svansnoden.
Pseudokoden för att infoga en nod längst ner på en enda lista:
function insertAtEnd( head, value ): newNode = Node(value) if head is NULL: head = newNode return head while head.next is not NULL: then head = head.next head.next = newNode newNode.next = NULL
Infogning efter en nod i en Singly Linked List
Att infoga efter en nod har två delar: Sök efter noden och bifoga efter den sökta noden. Vi måste korsa alla noder. För varje nod måste vi matcha med sökelementet. Om det finns en matchning kommer vi att lägga till den nya noden efter den sökta noden.
Här är stegen:
Steg 1) Gå igenom nästa nod tills värdet på den aktuella noden är lika med sökobjektet.
Steg 2) Den nya nodens nästa pekare kommer att vara den nuvarande nodens nästa pekare.
Steg 3) Den nuvarande nodens nästa nod kommer att vara den nya noden.
Här är pseudokoden för att infoga en nod efter en nod:
function insertAfter( head, value, searchItem ): newNode = Node(value) while head.value equals searchItem: then head = head.next newNode.next = head.next.next head.next = newNode
Infogning före en nod i en Singly Linked List
Denna funktion är mycket lik insättningen efter en nod. Vi måste skapa en ny nod och gå igenom den länkade listan tills den aktuella noden matchar söknoden. Efter det kommer vi att lägga till den nya noden som den tidigare noden för den aktuella noden.
Här är stegen:
Steg 1) Traversera tills nästa nods värde är lika med sökobjektet.
Steg 2) Skapa en ny nod och tilldela nodens "nästa" med nästa till nästa nod i den aktuella noden.
Steg 3) Tilldela den nya noden som nästa nod för den aktuella noden.
Här är pseudokoden:
function insertBefore( head, value, searchItem ): newNode = Node(value) while head.next.value equals searchItem: then head = head.next newNode.next = head.next.next head.next = newNode
Ta bort huvudet på den enkellänkade listan
I varje funktion i den länkade listan tillhandahålls huvudpekaren som parameter. Du måste ta bort huvudnoden och göra nästa nod för huvudnoden som den nya huvudnoden för den länkade listan. Vi måste också frigöra minnet för den borttagna noden. Annars kommer minnet att markeras som upptaget när ett annat program försöker komma åt det.
Här är stegen för att ta bort huvudet på den enkellänkade listan:
Steg 1) Tilldela nästa nod i huvudnoden som det nya huvudet.
Steg 2) Frigör det tilldelade minnet av den föregående huvudnoden.
Steg 3) Returnera den nya huvudnoden.
Pseudokoden för att ta bort huvudnoden:
function deleteHead( head ): temp = head head = head.next free( temp ) return head
Ta bort svansen på den enkellänkade listan
Att ta bort svansnoden är mer bekant med att ta bort huvudnoden. Skillnaden är att vi måste gå till slutet av den länkade listan och ta bort den. I den enkellänkade listan är noden med nästa nod som "NULL" svansnoden.
Här är stegen för att ta bort svansnoden i den länkade listan:
Steg 1) Traverse före svansnoden. Spara den aktuella noden.
Steg 2) Frigör minnet för nästa nod i den aktuella noden.
Steg 3) Ställ in nästa nod för den aktuella noden som NULL.
Här är pseudokoden för att ta bort svansnoden:
function deleteTail( head ): while head.next.next is not NULL: head = head.next free( head.next ) head.next = NULL
Sök och ta bort en nod från en enskild länkad lista
Denna funktion har två uppgifter, sök och radera. Vi måste söka till slutet av de enkellänkade listorna. Om vi hittar någon liknande nod kommer vi att ta bort den. Efter det måste vi slå samman eller länka vänster och höger noder för den borttagna noden. Här är stegen för att göra detta:
Steg 1) Gå till slutet av den länkade listan. Kontrollera om den aktuella noden är lika med söknoden eller inte.
Steg 2) Om någon nod matchar, lagra nodpekaren till den aktuella noden.
Steg 3) "Nästa" av föregående nod kommer att vara nästa nod för den aktuella noden.
Steg 4) Ta bort och frigör minnet för den aktuella noden.
Pseudokod för sökning och radering av en nod från en enkellänkad lista:
function searchAndDelete( head, searchItem ): while head.next.next is not NULL and head.next.value is not equals searchItem : head = head.next head.next = head.next.next delete(head.next)
Gå igenom en enskild länkad lista
Enbart länkad lista har bara funktionen för att korsa topp till svans. Det finns inga pekare till föregående nod; det är därför vi inte kan gå igenom den enkellänkade listan i omvänd ordning. Vi kommer att korsa varje nod och skriva ut den aktuella nodens värde tills vi får null.
Här är stegen:
Steg 1) Traversera varje nod tills vi får noll som nästa nod.
Steg 2) Skriv ut värdet för den aktuella noden.
Pseudokod för att gå igenom en enkellänkad lista:
function traverse( head ): while head.next is not NULL: print the value of the head head = head.next
Exempel på Singly Linked List in C++
#include<iostream> using namespace std; struct Node{ int data; struct Node *next; }; void insertAtHead(Node* &head, int value){ Node* newNode = new Node(); newNode->data = value; newNode->next = NULL; if(head!=NULL){ newNode->next = head; } head = newNode; cout<<"Added "<<newNode->data<<" at the front"<<endl; } void insertEnd(Node* &head, int value){ if(head==NULL){ insertAtHead(head,value); } Node* newNode = new Node(); newNode->data = value; newNode->next = NULL; Node *temp = head; while(temp->next!=NULL){ temp = temp->next; } temp->next = newNode; cout<<"Added "<<newNode->data<<" at the end"<<endl; } void searchAndDelete(Node **headPtr, int searchItem){ Node *temp = new Node(); if( (*headPtr)->data == searchItem ){ temp = *headPtr; *headPtr = (*headPtr)->next; free(temp); }else{ Node *currentNode = *headPtr; while(currentNode->next != NULL){ if(currentNode->next->data == searchItem){ temp = currentNode->next; currentNode->next = currentNode->next->next; free(temp); }else{ currentNode = currentNode->next; } } } cout<<"Deleted Node\t"<<searchItem<<endl; return; } void insertAfter(Node * &headPtr, int searchItem, int value){ Node* newNode = new Node(); newNode->data = value; newNode->next = NULL; Node *head = headPtr; while(head->next!=NULL && head->data!=searchItem){ head = head->next; } newNode->next = head->next; head->next = newNode; cout<<"Inserted "<<value<<" after node\t"<<searchItem<<endl; } void insertBefore(Node * &headPtr, int searchItem, int value){ Node* newNode = new Node(); newNode->data = value; newNode->next = NULL; Node *head = headPtr; while(head->next!=NULL && head->next->data!=searchItem){ head = head->next; } newNode->next = head->next; head->next = newNode; cout<<"Inserted "<<value<<" before node\t"<<searchItem<<endl; } void traverse(Node *headPointer){ Node* tempNode = new Node(); tempNode = headPointer; cout<<"Traversal from head:\t"; while(tempNode !=NULL){ cout<<tempNode->data; if(tempNode->next) cout<<" --> "; tempNode = tempNode ->next; } cout<<endl; } int main(){ Node *head = NULL; insertAtHead(head,5); insertAtHead(head,6); insertAtHead(head,7); insertEnd(head,9); traverse(head); searchAndDelete(&head,6); traverse(head); insertAfter(head,7,10); insertBefore(head,9,11); traverse(head); }
Produktion:
Added 5 at the front Added 6 at the front Added 7 at the front Added 9 at the end Traversal from head: 7 → 6 → 5 → 9 Deleted Node 6 Traversal from head: 7 → 5 → 9 Inserted 10 after node 7 Inserted 11 before node 9 Traversal from head: 7 → 10 → 5 → 11 → 9
Exempel på Singly Linked List in Python Prográmma
class Node: def __init__(self,data = None, next = None): self.data = data self.next = next class SinglyLinkedList: def __init__(self): self.head = None def insertAtHead(self, value): newNode = Node(data=value) if self.head is not None: newNode.next = self.head self.head = newNode print(f'Added {newNode.data} at the front.') return def insertAtEnd(self,value): if self.head is None: self.insertAtHead(value) newNode = Node(value) temp = self.head while temp.next is not None: temp = temp.next temp.next = newNode print(f'Added {newNode.data} at the end.') def searchAndDelete(self,searchItem): temp = Node() if self.head is searchItem: temp = self.head self.head = self.head.next else: currentNode = self.head while currentNode.next is not None: if currentNode.next.data is searchItem: temp = currentNode.next currentNode.next = currentNode.next.next else: currentNode = currentNode.next print(f'Deleted node\t{searchItem}') return def insertAfter(self,searchItem,value): newNode = Node(data=value) temp = self.head while temp.next is not None and temp.data is not searchItem: temp = temp.next newNode.next = temp.next temp.next = newNode print(f'Inserted {value} after node\t{searchItem}') return def insertbefore(self,searchItem,value): newNode = Node(data=value) temp = self.head while temp.next is not None and temp.next.data is not searchItem: temp = temp.next newNode.next = temp.next temp.next = newNode print(f'Inserted {value} before node\t{searchItem}') return def traverse(self): temp = self.head print("Traversing from head:\t",end="") while temp: print("{}\t".format(temp.data),end="") temp = temp.next print() SinglyLinkedList = SinglyLinkedList() SinglyLinkedList.insertAtHead(5) SinglyLinkedList.insertAtHead(6) SinglyLinkedList.insertAtHead(7) SinglyLinkedList.insertAtEnd(9) SinglyLinkedList.traverse() SinglyLinkedList.searchAndDelete(6) SinglyLinkedList.traverse() SinglyLinkedList.insertAfter(7,10) SinglyLinkedList.insertbefore(9, 11) SinglyLinkedList.traverse()
Produktion:
Added 5 at the front. Added 6 at the front. Added 7 at the front. Added 9 at the end. Traversing from head: 7 6 5 9 Deleted node 6 Traversing from head: 7 5 9 Inserted 10 after node 7 Inserted 11 before node 9 Traversing from head: 7 10 5 11 9
Komplexiteten av enbart länkad lista
Det finns två typer av komplexitet: tidskomplexitet och rymdkomplexitet. Den värsta och genomsnittliga falltidskomplexiteten är densamma för listan med enkel länk.
Tidskomplexiteten för bästa fall:
- Insättning i huvudet kan göras i O(1). Eftersom vi inte behöver gå inuti den länkade listan.
- Sök- och raderingsoperation kan göras i O(1) om sökelementet finns i huvudnoden.
Tidskomplexiteten för det genomsnittliga fallet:
- Infogning i en länkad lista kommer att ta O(n) om "n" element finns i listan med enkel länk.
- Sök och ta bort kan också ta O(n), eftersom sökelementet kan finnas i svansnoden. I så fall bör du gå igenom hela listan.
Utrymmeskomplexiteten för enbart länkad lista
Singly Linked List allokerar dynamiskt minne. Om vi vill lagra n element kommer den att allokera n minnesenhet. Så rymdkomplexiteten är O(n).