Linkelt lista

A linkelt lista az egyik legegyszerűbb adatstruktúra. Ez egy csomópontok tömbje, amelyek mutatókkal vannak összekötve.

A lista minden csomópontja tartalmaz egy értéket és egy mutatót a lista következő csomópontjára. Ez a viselkedés lehetővé teszi, hogy a csatolt lista dinamikus tömbként viselkedjen, ahol a méret nincs rögzítve, és még a létrehozása után is módosítható (a hagyományos statikus tömböktől eltérően).

A linkelt listának a három alapvető műveletet támogatnia kell: keresés, beillesztés és törlés.

Futási idők

Beszúrás:

  • Beszúrás az elején: O(1)
  • Beszúrás a végén: O(n) (legrosszabb esetben, amikor a végére kell haladnunk, hogy új csomópontot szúrjunk be)
  • Beszúrás egy adott pozícióba: O(n) (legrosszabb esetben, amikor az adott pozícióba kell áthaladnunk egy új csomópont beillesztéséhez)

Törlés:

  • Törlés az elején: O(1)
  • Törlés a végén: O(n) (legrosszabb esetben, amikor a végére kell haladnunk egy csomópont törléséhez)
  • Törlés egy adott pozícióban: O(n) (legrosszabb esetben, amikor egy csomópont törléséhez az adott pozícióba kell áthaladnunk)

Keresés: O(n) (a legrosszabb esetben, amikor a lista összes elemén keresztül kell haladnunk, hogy megtaláljunk egy adott elemet)

Linkelt lista megvalósítása

1. Hivatkozott lista létrehozása

Először hozzuk létre a Node osztályt a lista csomópontjainak megjelenítésére. Mint említettük, minden csomópontnak van értéke és egy mutatója a következő csomópontra.

class Node:
    def __init__(self, value, next = None) -> None:
        self.value = value
        self.next = next

Ezután a LinkedList osztály. Hozzáadom a __repr__ metódust is, hogy ki tudjuk nyomtatni a lista elemeit.

class LinkedList:
    def __init__(self, head: Node = None):
        """
        # Consturctor #1 - Empty Linked List
        """
        self.head = head

  def __repr__(self):
        """
        Print Linked List
        """
        items = ''
        current_node = self.head
        while current_node != None:
            items += str(current_node.value) + '-->'
            current_node = current_node.next
        return f"LinkedList({items[:-3]})"

Nézzük meg, hogyan hozhatunk létre linkelt listát:

# Creating a linked list
head = Node(2)
head.next = Node(1)
head.next.next = Node(4)
head.next.next.next = Node(3)
head.next.next.next.next = Node(5)
head.next.next.next.next.next = Node(6)

linked_list = LinkedList(head)

# print list
print(linked_list)

# Output:
# LinkedList(2-->1-->4-->3-->5-->6)

Ezután létrehozhatunk egy második konstruktort az osztályhoz, amely lehetővé teszi a linkelt listák könnyebb létrehozását. Tegyük fel, hogy lehetővé akarjuk tenni a felhasználók számára, hogy értéklista átadásával linkelt listákat hozzanak létre. Megtehetjük így:

class LinkedList:
    def __init__(self, head: Node = None):
        """
        # Consturctor #1 - Empty Linked List
        """
        self.head = head

  def __repr__(self):
        """
        Print Linked List
        """
        items = ''
        current_node = self.head
        while current_node != None:
            items += str(current_node.value) + '-->'
            current_node = current_node.next
        return f"LinkedList({items[:-3]})"

  @classmethod
    def generate_list(cls, *args):
        """
        Constructor #2 - Generate Linked List from list of values
        """
        head = Node(args[0])
        current_node = head
        for value in args[1:]:
            current_node.next = Node(value)
            current_node = current_node.next

        return cls(head = head)

Mostantól sokkal könnyebben hozhatunk létre egy linkelt listát:

linked_list = LinkedList.generate_list(2,1,4,3,5,6)
print(linked_list)

# Output
# LinkedList(2-->1-->4-->3-->5-->6)

2. Keresés

Az érték keresése egy linkelt listában magában foglalja a listán való bejárást, amíg el nem érjük a None értéket (lista vége), vagy meg nem találjuk a keresett értékkel rendelkező csomópontot.

class Node:
    def __init__(self, value, next = None) -> None:
        self.value = value
        self.next = next

class LinkedList:
    def __init__(self, head: Node = None):
        """
        # Consturctor #1 - Empty Linked List
        """
        self.head = head

    @classmethod
    def generate_list(cls, *args):
        """
        Constructor #2 - Generate Linked List from list of values
        """
        head = Node(args[0])
        current_node = head
        for value in args[1:]:
            current_node.next = Node(value)
            current_node = current_node.next

        return cls(head = head)
    
    def __repr__(self):
        """
        Print Linked List
        """
        items = ''
        current_node = self.head
        while current_node != None:
            items += str(current_node.value) + '-->'
            current_node = current_node.next
        return f"LinkedList({items[:-3]})"
        
    def index(self, index):
        """
        Seach a value in Linked List. Return -1 if not found
        Description:
            - Iterate through the linked list
            - If value is found, return the value
            - If value is not found, return -1
        """
        current_node = self.head
        while current_node != None:
            if index == 0:
                return current_node.value
            else:
                index -= 1
                current_node = current_node.next
        return -1

Lássunk egy példát:

linked_list = LinkedList.generate_list(2,1,4,3,5,6)
print(linked_list.index(2)) 

# Output:
# 4

2. Helyezze be

Hasonló logika a kereséshez. Haladjon végig a listán, amíg el nem éri a kívánt indexhelyet. Hozzon létre egy csomópontot, és helyezze be a listában arra a helyre.

Ezután frissítenünk kell a listában szereplő hivatkozásokat. Az új csomópontnak a lista következő csomópontjára kell mutatnia. Az előző csomópontnak pedig az új csomópontra kell mutatnia.

class Node:
    def __init__(self, value, next = None) -> None:
        self.value = value
        self.next = next

class LinkedList:
    def __init__(self, head: Node = None):
        """
        # Consturctor #1 - Empty Linked List
        """
        self.head = head

    @classmethod
    def generate_list(cls, *args):
        """
        Constructor #2 - Generate Linked List from list of values
        """
        head = Node(args[0])
        current_node = head
        for value in args[1:]:
            current_node.next = Node(value)
            current_node = current_node.next

        return cls(head = head)
    
    def __repr__(self):
        """
        Print Linked List
        """
        items = ''
        current_node = self.head
        while current_node != None:
            items += str(current_node.value) + '-->'
            current_node = current_node.next
        return f"LinkedList({items[:-3]})"
        
    def index(self, index):
        """
        Seach a value in Linked List. Return -1 if not found
        Description:
            - Iterate through the linked list
            - If value is found, return the value
            - If value is not found, return -1
        """
        current_node = self.head
        while current_node != None:
            if index == 0:
                return current_node.value
            else:
                index -= 1
                current_node = current_node.next
        return -1

    def insert(self, value, index):
        """
        Insert a value at a given index
        """
        if len(self) < index:
            print("Index not in Range")
            return None

        current_node = self.head
        while current_node != None:
            if index == 1:
                next = current_node.next 
                current_node.next = Node(value) 
                current_node.next.next = next
                return 
            else:
                index -= 1
                current_node = current_node.next

  def __len__(self):
        """
        Return the length of the linked list
        """
        current_node = self.head
        counter = 0
        while current_node != None:
            counter += 1
            current_node = current_node.next
        return counter

Lássunk egy példát:

# Creating a linked list
linked_list = LinkedList.generate_list(2,1,4,3,5,6)

# Inserting a value
linked_list.insert(value=20, index=2)

# Print list
print(linked_list)

# Output:
# LinkedList(2-->1-->20-->4-->3-->5-->6)

3. Törlés

Egy csomópont törléséhez meg kell találnunk a csomópontot, majd törölnünk kell. Ezután frissítenünk kell az előző és a következő csomópont mutatóit, hogy egymásra mutassanak.

class Node:
    def __init__(self, value, next = None) -> None:
        self.value = value
        self.next = next

class LinkedList:
    def __init__(self, head: Node = None):
        """
        # Consturctor #1 - Empty Linked List
        """
        self.head = head

    @classmethod
    def generate_list(cls, *args):
        """
        Constructor #2 - Generate Linked List from list of values
        """
        head = Node(args[0])
        current_node = head
        for value in args[1:]:
            current_node.next = Node(value)
            current_node = current_node.next

        return cls(head = head)
    
    def __repr__(self):
        """
        Print Linked List
        """
        items = ''
        current_node = self.head
        while current_node != None:
            items += str(current_node.value) + '-->'
            current_node = current_node.next
        return f"LinkedList({items[:-3]})"
        
    def index(self, index):
        """
        Seach a value in Linked List. Return -1 if not found
        Description:
            - Iterate through the linked list
            - If value is found, return the value
            - If value is not found, return -1
        """
        current_node = self.head
        while current_node != None:
            if index == 0:
                return current_node.value
            else:
                index -= 1
                current_node = current_node.next
        return -1

    def insert(self, value, index):
        """
        Insert a value at a given index
        """
        if len(self) < index:
            print("Index not in Range")
            return None

        current_node = self.head
        while current_node != None:
            if index == 1:
                next = current_node.next 
                current_node.next = Node(value) 
                current_node.next.next = next
                return 
            else:
                index -= 1
                current_node = current_node.next

    def delete(self, index):
        """
        Delete a node at specifc index
        """
        current_node = self.head
        while current_node != None:
            if index == 1:
                current_node.next = current_node.next.next
                break
            else:
                index -= 1
                current_node = current_node.next
        
    def __len__(self):
        """
        Return the length of the linked list
        """
        current_node = self.head
        counter = 0
        while current_node != None:
            counter += 1
            current_node = current_node.next
        return counter

Lássunk egy példát:

# Creating a linked list
linked_list = LinkedList.generate_list(2,1,4,3,5,6)

# Delete the node at index 2
linked_list.delete(index=2)

# Print list
print(linked_list)

# Output:
# LinkedList(2-->1-->3-->5-->6)

Vegye figyelembe, hogy ez a megvalósítás a linkelt lista alapformája, testreszabhatjuk és kell is, hogy megfeleljen az igényeinknek. Ezenkívül a Python két beépített adatstruktúrával rendelkezik, amelyek linkelt listaként viselkedhetnek, ezek a Lists és collections.deque. A legtöbb esetben jobb lenne, ha ezt a két adatstruktúrát használnánk.

Ha nincs szükség speciális testreszabásra, akkor először ezeket a beépített adatstruktúrákat kell használnunk. A linkelt listák hasznosabbak olyan nyelvekben, mint a C, amelyek statikus tömböket tartalmaznak. Az adatstruktúra megvalósításának ismerete azonban hasznos lehet bizonyos helyzetekben, és hozzájárul ahhoz, hogy jobban megértse, hogyan épülnek fel és hogyan viselkednek más adatstruktúrák.