Bağlı Liste (Linked List)
Elemanları işaretçilerle birbirine bağlı düğümler olarak saklayan veri yapısı.
#Nasıl çalışır?
Bağlı liste (linked list), elemanları bellekte yan yana değil, birbirine işaretçilerle (pointer) bağlı düğümler (node) olarak saklar. Her düğüm bir değer ve bir sonraki düğümün adresini (next) tutar.
Listenin ilk düğümünü head gösterir, son düğümün next işaretçisi ise null'dır. Bir elemana ulaşmak için head'den başlayıp next işaretçilerini tek tek takip etmek gerekir.
Diziden en büyük farkı şudur: araya eleman eklemek ya da silmek için diğer elemanları kaydırmak gerekmez, yalnızca birkaç işaretçi değişir. Buna karşılık i'inci elemana doğrudan atlanamaz.
#Kendin dene
Bir değer yazıp başa, sona ya da belirli bir sıraya ekle; silme ve aramada düğümlerin tek tek gezildiğini izle.
#Temel işlemler
- insertHead(x)
- Yeni düğümü başa ekler: yeni düğüm eski head'i gösterir, head yeni düğüm olur.
- insertTail(x)
- Son düğüme kadar gidip yeni düğümü sona bağlar. Bir tail işaretçisi tutulursa O(1) olur.
- insertAt(i, x)
- i - 1'inci düğüme kadar gider, yeni düğümü araya bağlar.
- remove(x)
- x değerli düğümü bulur; önceki düğümün next işaretçisini bir sonrakine bağlayarak onu listeden çıkarır.
- search(x)
- head'den başlayıp düğümleri tek tek kontrol eder.
#Örnek kod
Aynı algoritma 8 dilde. Her program derlenip çalıştırılarak test edildi ve hepsi aynı çıktıyı veriyor.
from __future__ import annotations
from dataclasses import dataclass
@dataclass
class Node:
value: int
next: Node | None = None
class LinkedList:
def __init__(self) -> None:
self.head: Node | None = None
def push_front(self, value: int) -> None:
# O(1): the new node simply points at the old head.
self.head = Node(value, self.head)
def push_back(self, value: int) -> None:
# O(n): walk to the last node (a tail pointer would make this O(1)).
node = Node(value)
if self.head is None:
self.head = node
return
cur = self.head
while cur.next is not None:
cur = cur.next
cur.next = node
def index_of(self, value: int) -> int:
cur, i = self.head, 0
while cur is not None:
if cur.value == value:
return i
cur, i = cur.next, i + 1
return -1
def remove(self, value: int) -> None:
# Unlinks the first node with this value: the previous node skips over it.
if self.head is None:
return
if self.head.value == value:
self.head = self.head.next
return
prev = self.head
while prev.next is not None and prev.next.value != value:
prev = prev.next
if prev.next is not None:
prev.next = prev.next.next
def __str__(self) -> str:
values, cur = [], self.head
while cur is not None:
values.append(str(cur.value))
cur = cur.next
return " ".join(values)
items = LinkedList()
items.push_front(2)
items.push_front(1)
items.push_back(3)
print(items) # 1 2 3
print(items.index_of(2)) # 1
items.remove(2)
print(items) # 1 3#Karmaşıklık
| İşlem | Süre |
|---|---|
| Başa ekleme / baştan silme | O(1) |
| Sona ekleme (tail işaretçisiyle) | O(1) |
| Sona ekleme (tail olmadan) | O(n) |
| i'inci elemana erişim | O(n) |
| Arama | O(n) |
| Bilinen bir düğümden sonra ekleme/silme | O(1) |
Bağlı listenin gücü ekleme ve silmede: doğru düğüme ulaşıldıktan sonra yalnızca işaretçiler değişir. Zayıf yanı erişim: dizide a[i] O(1) iken bağlı listede i düğüm gezmek gerekir. Ayrıca düğümler bellekte dağınık durduğu için önbellek (cache) kullanımı diziden kötüdür.
#Ne zaman kullanılır?
Başa ya da ortaya sık ekleme/silme yapılan ve rastgele erişimin gerekmediği durumlarda kullanılır: LRU önbellekleri (çift yönlü bağlı liste + hash tablosu), işletim sistemindeki boş bellek listeleri, yığın ve kuyruk gerçeklemeleri. Çoğu günlük işte dinamik diziler (ArrayList, Python list) daha hızlıdır.
#Alıştırma
Soruları cevaplamak ve ilerlemeni kaydetmek için giriş yap.
Kolay
Tekli bağlı listede her düğüm ne tutar?
- 1Bir değer ve sonraki düğümün adresi
- 2Yalnızca bir değer
- 3Bir değer ve indeksi
- 4Tüm listenin uzunluğu
Bağlı listede i'inci elemana erişmenin karmaşıklığı nedir?
- 1O(n)
- 2O(1)
- 3O(log n)
- 4O(n²)
Listenin başına eleman eklemenin karmaşıklığı nedir?
- 1O(1)
- 2O(n)
- 3O(log n)
- 4O(n²)
Orta
head → 4 → 7 → 2 → null listesinde 7 silinirse hangi işaretçi değişir?
- 14'ün next işaretçisi 2'yi gösterir
- 2head 7'yi gösterir
- 32'nin next işaretçisi 4'ü gösterir
- 4Hiçbiri, elemanlar kaydırılır
Zor
Bağlı liste hangi durumda diziden daha uygun bir seçimdir?
- 1Ortaya ve başa sık ekleme/silme yapılıp rastgele erişim gerekmediğinde
- 2Elemanlara sık sık indeksle erişildiğinde
- 3İkili arama yapılacağında
- 4Önbellek verimliliği önemli olduğunda
#Bundan sonra
Bu dersi bildiğini varsayan dersler: