Linklangan listlar (Linked lists)
Linklangan listlar unchalik taniqli bo'lmagan pythondagi odatiy listlar avlodidir. Lekin linklangan listlar bazi vaziyatlarda odatiy listlarga qaraganda ishlatish uchun eng to'g'ri tanlov.
Linklangan listlar tartiblangan obyektlar jamlanmasidir. Linklangan listlarning odatiy listlardan farqi ular elementlarni xotirada odatiy listlarga qaraganda boshqacharoq saqlaydi. Odatiy listlar xotira blocklarida o'z elementlariga reference lar saqlaydi, Linklangan listlar esa referencelarni elementining bir qismi sifatida saqlaydi.
Asosiy tushuncha
Linklangan listlarning elementlari node deb ataladi, har bitta nodaning ikkita maydoni bo'ladi
- Data: nodada saqlanadigan malumot
- Next: keyingi nodaga havola
Odatiy nodaning ko'rinishi:
Linklangan listlar nodalar kolleksiyasidir. Birinchi noda head deb ataladi, u linklangan list ustida bajariladigan istalgan interatsiyaning boshlang'ich nuqtasi hisoblanadi. Oxirgi nodaning next maydonidagi havola None bo'lishi zarur, sababi uning oxirgi nodaligini faqat shunaqa qilib bildirish mumkin.
Amaliy dasturlar
Linked listlar amalda queue, stack yoki graph larni realizatsiya qilishda qo'l keladi.
Queue - Navbat yoki Stack - Taxmon
Queue bilan Stack faqat bir biridan elementlarni olish usuli bilan farq qiladi. Queue uchun biz First-In/First-Out (FIFO) usulini ishlatamiz. Bu degani birinchi qo'shilgan element birinchi chiqarib olinadi.
Yuqoridagi rasmda ko'rib turibsiz, queue ikkita tomoni bor, birinchisi front ikkinchisi rear. Elemement qo'shilganda rear tomondan qo'shiladi, chiqarilganda esa front tomondan chiqariladi, yani birinchi qo'shilgan element birinchi bo'lib chiqadi.
Stack uchun esa biz Last-In/First-Out nazariyasini ishlatamiz (LIFO). Bu degani oxirgi qo'shilgan element birinchi bo'lib chiqariladi.
Rasmda ko'rganingizdek, birinchi kiritilgan element yani indexi 0 bolgan element eng pastda, eng oxirgi qo'shilgan element esa eng tepada.
Graf (Graph)
Graflar obyektlar orasidagi bog'liqlikni ko'rsatish orqali qandaydur networkni namoyon qilish uchun ishlatiladi. Misol uchun Directed Acyclic graph (DAG) - (Yo'naltirilgan lekin siklga ega bo'lmagan graf)
Grafni turli xil ko'rinishda implement qilish mumkin, va ulardan biri adjecency list (Qo'shnilik ro'yhati. Grafning qirrasini uning qo'shni qirralariga bog'liqligini namoyon qiluvchi tartiblanmagan list). Adjecency list linklangan listlar ro'yhati bo'lib unda grafning har bir qirrasi va unga qo'shni bo'lgan qirralar birgalikda saqlanadi.
Vertex | Linked List of Vertices |
---|---|
1 | 2 → 3 → None |
2 | 4 → None |
3 | None |
4 | 5 → 6 → None |
5 | 6 → None |
6 | None |
Xuddi shu ulangan listni Pythonda quyidagicha ko'rsatilishi ham mumkin.
>>> graph = {
... 1: [2, 3, None],
... 2: [4, None],
... 3: [None],
... 4: [5, 6, None],
... 5: [6, None],
... 6: [None]
... }
Ushbu dictionary dagi keylar source qirralardir, uning valuelari yani listlar bo'lsa shu qirraga qo'shni bo'lgan qirralarning.
Ishlash unumdorligini taqqoslash: Listlar va linklangan Listlar (Performance comparison: Lists vs Linked Lists)
Ko'p dasturlash tillarida linklangan listlar va odatiy listlarning xotirada saqlanishida aniq farqlar bor. Pythonda esa ikkalasi ham bir xil usulda xotirada saqlanadi. Shuning uchun unumdorlik haqida o'ylaganimizda Pythonda linklangan list va odatiy listlarning biror operatsiyani bajarishga ketadigan vaqti nuqtai nazardan taqqoslashimiz to'g'ri bo'ladi.
Element qo'shish va o'chirish
Pythonda listga element qo'shish uchun insert() yoki append() ishlatamiz. O'chirish uchun esa pop() yoki remove(). Ushbu metodlarning bir biridan farqi shundaki insert() va remove() odatiy holatda listning boshidagi elementlar ustida amal bajaradi, pop() va append() esa listning oxiridagi elementlar ustida amal bajaradi.
Bilishimiz joiz bo'lgan narsa, insert() va remove() ishlatilganda parda ortida elementlarni shift qilish talab etiladi va o'z o'rnida bu operatsiyalar ham qo'shimcha vaqt talab qiladi. Biz insert() yoki append() metodlarini listning oxiriga ishlatadigan bo'lsak unga konstant vaqt ketadi O(1), agar biz list metodlarini listning boshida yoki boshiga yaqin qo'llaydigan bo'lsak ushbu metodlar list hajmi ortgani sari operatsiyani bajarilishiga ketadigan vaqt ham proportsional tarzda oshadi O(n).
Linklangan listlar esa element o'chirish yoki qo'shishga kelganda unumdor hisoblanadi, yani u listning boshidami oxiridami farqi yo'q ketadigan vaqt O(1) bo'ladi.
Ushbu jihatda queue (FIFO) qilib ishlatganda linked listlar odatiy listlardan tezroq ishlaydi. Sababi Queueda element boshiga qo'shiladi va boshidan o'chiradi. Lekin linklangan listlarda Stackni implement qiladigan bo'lsak (LIFO) unda odatiy list bilan o'xshash ishlaydi. Sababi elementlar oxiridan qo'shiladi va o'chiriladi.
Elementlarni olish
Elementlarni olishga qolganda listlar linked listlarga qaraganda ancha tez ishlaydi. Agar biz qaysi element bizga kerakligini bilsa listdan uni O(1) vaqtda chiqarib olishimiz mumkin. Xuddi shu ishni linked listda bajaradigan bo'lsak O(n) vaqt ketadi, sababi berilgan elementni topish uchun butun listni aylanib chiqish kerak bo'ladi.
Malum elementli izlashga qolganda ikkala list ham bir xil ishlaydi. Ikkala holatda ham biz listni to'liq iteratsiya qilib chiqishimiz kerak bo'ladi.
collections.deque bilan tanishamiz
Pythonning collections modulida linklangan listlarni implement qilish uchun deque deb nomlangan maxsus obyekt bor, double-ended-queue.
collections.deque linklangan listlarda elementlarni olish, o'chirish, qo'shish, boshidan yoki oxiridan farqi yo'q, barchasini O(1) vaqtda bajaradi.
collections.deque dan foydalanish
Deque o'zi bilan bir nechta metodlarni olib keladi.
Birinchi linked list yasaymiz:
>>> from collections import deque
>>> deque()
deque([])
yuqoridagi kod bo'sh linklangan list yasaydi. Yaratgan zahotimiz uni elementlar bilan to'ldirishimiz mumkin, buning uchun argument sifatida istalgan iterable berib yuborsak bas:
>>> deque(['a','b','c'])
deque(['a', 'b', 'c'])
>>> deque('abc')
deque(['a', 'b', 'c'])
>>> deque([{'data': 'a'}, {'data': 'b'}])
deque([{'data': 'a'}, {'data': 'b'}])
deque ga stringni argument sifatida berib, unga element qo'shib va o'chirib ko'ramiz:
>>> llist = deque("abcde")
>>> llist
deque(['a', 'b', 'c', 'd', 'e'])
>>> llist.append("f")
>>> llist
deque(['a', 'b', 'c', 'd', 'e', 'f'])
>>> llist.pop()
'f'
>>> llist
deque(['a', 'b', 'c', 'd', 'e'])
Bu yerda append() ham pop() ham elementning oxirida amalga oshadi. Ammo biz deque bilan bemalol ushbu operatsiyalarni linked list boshida bajarishim ham mumkin:
>>> llist.appendleft("z")
>>> llist
deque(['z', 'a', 'b', 'c', 'd', 'e'])
>>> llist.popleft()
'z'
>>> llist
deque(['a', 'b', 'c', 'd', 'e'])
Queue va Stackni implement qilish
Queue - Navbat
Queueni implement qilishda siz listga yangi value qo'shib queue yaratasiz (enqueue), vaqti kelganda eng uzoq vaqt queueda qolgan elementni o'chirasiz (dequeue).
>>> from collections import deque
>>> queue = deque()
>>> queue
deque([])
>>> queue.append("Mary")
>>> queue.append("John")
>>> queue.append("Susan")
>>> queue
deque(['Mary', 'John', 'Susan'])
Hozir sizdagi navbatda Mary, John, va Susan bor, esingizda bo'lsin queue FIFO qonuniga bo'ysunadi, yani birinchi queuega kirgan element birinchi bo'lib chiqib ketadi.
Bir oz vaqt o'tgach navbatda turganlar uchun stollarda joylar bo'shaydi va siz navbatga eng birinchi kelgan element ni queuedan mana bu tarzda o'chirasiz:
>>> queue.popleft()
'Mary'
>>> queue
deque(['John', 'Susan'])
>>> queue.popleft()
'John'
>>> queue
deque(['Susan'])
har doim siz queuedan popleft() orqali element o'chirsangiz parda ortida linked listdan head element o'chadi, shu tariqa siz queueni implement qilgan bo'lasiz.
Stack - taxmon
Stack yaratmoqchi bo'lsangizchi, g'oya juda ham queuega o'xshash, yagona farq stacklar LIFO qonuniga bo'ysunadi, bu degani stackga oxirgi qo'shilgan elementni birinchi bo'lib olib tashlasa bo'ladi.
Tasavur qiling, siz web browser tarixi funksiyasini implement qilmoqchisiz, browser tarixida siz bemalol oxirgi kirgan websaytingizga birinchi bo'lib qaytolasiz.
Biz bu xusisiyatni stack yordamida quyidagicha amalga oshirishimiz mumkin:
>>> from collections import deque
>>> history = deque()
>>> history.appendleft("https://realpython.com/")
>>> history.appendleft("https://realpython.com/pandas-read-write-files/")
>>> history.appendleft("https://realpython.com/python-csv/")
>>> history
deque(['https://realpython.com/python-csv/',
'https://realpython.com/pandas-read-write-files/',
'https://realpython.com/'])
Bu misolda siz birinchi bo'sh browser tarixi yaratdingiz, va ketma ket unga uchta sayt urlini qo'shdingiz, appendleft() yordamida siz har bir urlni linked listni head qismiga qo'shdingiz.
Birozdan so'ng foydalanuvchi realpython websaytining bosh sahifasiga qaytishga qaror qildi, biz tarixni yaratishda stackdan foydalanganimizni bilgan xolda, oxirgi elementdan boshlab stackdan chiqarib tashlaymiz (LIFO):
>>> history.popleft()
'https://realpython.com/python-csv/'
>>> history.popleft()
'https://realpython.com/pandas-read-write-files/'
>>> history
deque(['https://realpython.com/'])
Va nixoyat, biz popleft() orqali elementlar qo'shilgan tomondan boshlab biz xoxlagan urlga yetib kelguncha elementlarni chiqarib tashladik, va ushbu namuna stackning real qo'llanishidir, bundan buyon stack yoki queuedagi challangelar bemalol pythonning collection modulidagi deque funksiyasi orqali amaliy stack yoki queue implement qilishimiz mumkin.
O'zingizni linklangan listingizni yarating
Linklangan listni qanaqa qilib yaratish mumkin.
Linklangan listimizni boshlash uchun class yaratib olamiz:
class LinkedList:
def __init__(self):
self.head = None
Linked listni saqlash uchun bizga kerak bo'ladigan yagona malumot bu listning qayerda boshlanishi yani head, biz uni yaratib oldik. Endi linked listning nodalarini implement qilish uchun boshqa class yaratamiz:
class Node:
def __init__(self, data):
self.data = data
self.next = None
Yuqoridagi class yaratilishida siz ikkita asosiy noda elementlarini ko'rishingiz mumkin, data va next, siz bunga yana __ repr __ method ham qo'shishingiz mumkin, instance haqida to'liqroq malumot bilan taminlash maqsadida:
class Node:
def __init__(self, data):
self.data = data
self.next = None
def __repr__(self):
return self.data
class LinkedList:
def __init__(self):
self.head = None
def __repr__(self):
node = self.head
nodes = []
while node is not None:
nodes.append(node.data)
node = node.next
nodes.append("None")
return " -> ".join(nodes)
Ushbu yaratilgan ikkita class orqali biz tezda uchta nodaga ega bo'lgan linked list yaratamiz.
>>> llist = LinkedList()
>>> llist
None
>>> first_node = Node("a")
>>> llist.head = first_node
>>> llist
a -> None
>>> second_node = Node("b")
>>> third_node = Node("c")
>>> first_node.next = second_node
>>> second_node.next = third_node
>>> llist
a -> b -> c -> None
Node ning data va next qiymatlarini berish orqali biz anchagina tez linked list yasashimiz mumkin. LinkedList va Node classlar bizning linked list implement qlishimizning boshlanishi, bundan buyogiga faqat funksionalni oshiramiz.
Linked list classning __ init __() metodiga linked listni malumot bilan to'ldirib olish uchun ozgina o'zgarish qilamiz:
def __init__(self, nodes=None):
self.head = None
if nodes is not None:
node = Node(data=nodes.pop(0))
self.head = node
for elem in nodes:
node.next = Node(data=elem)
node = node.next
Ushbu o'zgarishdan so'ng linked list yasash yanada tezroq bo'ladi.
Qanday qilib linked listni loop (traverse) qilish mumkin
Traverse sodda qilib aytgandan iteratsiya qilish. Demak biz traverse qilish uchun __ iter __() funksiyasini yaratamiz, shunda bizning linked list ham odatiy listga o'xshab loop qilish imkoniyatini beradi:
def __iter__(self):
node = self.head
while node is not None:
yield node
node = node.next
Ushbu metod listning har bir nodini yield qiladi. Muhimi __ iter __() metodida yield qilishdan oldin node ni None emasligini tekshring, sababi agar node Nonde bo'lsa biz linked listning oxiriga yetib kelgan bo'lamiz.
>>> llist = LinkedList(["a", "b", "c", "d", "e"])
>>> llist
a -> b -> c -> d -> e -> None
>>> for node in llist:
... print(node)
a
b
c
d
e
Yangi noda qo'shish
Yangi noda qo'shishning bir nechta usullari bor va har birining o'ziga yarasha qiyinchiligi bor, shuning uchun biz nodeni boshiga qo'shish, oxiriga qo'shish yoki qaysidur ikkita noda orasiga qo'shishni alohida funksiyalarga ajratib olamiz.
Boshidan qo'shish
Boshidan qo'shish bu eng osoni, sababi yangi elementni head deb belgilab qo'ysak bas, listni traverse qilishga xojat yo'q:
def add_first(self, node):
node.next = self.head
self.head = node
Ushbu metod quyidagicha ishlaydi:
>>> llist = LinkedList()
>>> llist
None
>>> llist.add_first(Node("b"))
>>> llist
b -> None
>>> llist.add_first(Node("a"))
>>> llist
a -> b -> None
Oxiriga qo'shish
Yangi nodeni oxiriga qo'shish uchun linked listni to'liq traverse qilishimiz kerak bo'ladi, next label None ga teng bo'lganda qo'shib qo'yamiz, oddiy listdagi kabi linked listda append qilib qo'yishning iloji yo'q, sababi biz oxirgi element qaysiligini bilmaymiz.
Ushbu metod bilan biz linked list oxiriga node qo'shamiz:
def add_last(self, node):
if self.head is None:
self.head = node
return
for current_node in self:
pass
current_node.next = node
Bu yerda for loop StopIteration Exception otgunicha linked listning o'zini loop qilaveramiz, loopdan chiqib ketganda bizning current_node o'zgaruvchimiz oxirgi nodaga teng bo'lgan bo'ladi, shunda biz oxirgi nodaning next referensini yangi nodaga qaratamiz, shunda oxirgi noda yangi qo'shilgan nodaga aylanadi.
misol:
>>> llist = LinkedList(["a", "b", "c", "d"])
>>> llist
a -> b -> c -> d -> None
>>> llist.add_last(Node("e"))
>>> llist
a -> b -> c -> d -> e -> None
>>> llist.add_last(Node("f"))
>>> llist
a -> b -> c -> d -> e -> f -> None
Ikkita noda orasiga noda qo'shish
Ikkita noda orasiga noda qo'shish, yani biz xoxlagan nodadan oldin yoki keyin noda qo'shish navbatdagi challange, uni amalga oshirish uchun ikkita metod yaratib olamiz:
- Berilgan nodadan keyin qo'shish
- Berilgan nodadan oldin qo'shish
Berilgan nodaning datasini qiymatiga qarab shu qiymatdan keyin noda qo'shish metodi:
def add_after(self, target_node_data, new_node):
if self.head is None:
raise Exception("List is empty")
for node in self:
if node.data == target_node_data:
new_node.next = node.next
node.next = new_node
return
raise Exception("Node with data '%s' not found" % target_node_data)
Bu yerda birinchi ishimiz biz izlayotgan dataga ega bo'lgan noda bor yo'qligi, biz izlayotgan datani topganimizda, list ketmaketligini buzmaslik uchun birinchi yangi nodaning next valuesini hozirgi nodaning next valuesiga tenglab olamiz, keyin hozirgi nodaning next valuesini yangi nodaga tenglaymiz.
Bu metodda ikkita exception qo'lladik, birinchisi list bo'sh bo'lsa xabar beradi, ikkinchisi esa biz izlagan dataga ega noda yo'q bo'lsa.
>>> llist = LinkedList()
>>> llist.add_after("a", Node("b"))
Exception: List is empty
>>> llist = LinkedList(["a", "b", "c", "d"])
>>> llist
a -> b -> c -> d -> None
>>> llist.add_after("c", Node("cc"))
>>> llist
a -> b -> c -> cc -> d -> None
>>> llist.add_after("f", Node("g"))
Exception: Node with data 'f' not found
add_before() metodi implement qilishga harakat qilamiz:
1 def add_before(self, target_node_data, new_node):
2 if self.head is None:
3 raise Exception("List is empty")
4
5 if self.head.data == target_node_data:
6 return self.add_first(new_node)
7
8 prev_node = self.head
9 for node in self:
10 if node.data == target_node_data:
11 prev_node.next = new_node
12 new_node.next = node
13 return
14 prev_node = node
15
16 raise Exception("Node with data '%s' not found" % target_node_data)
Bu yerda ayrim narsalarni eslab qolish juda muhim. Birinchi add_after() da qilganimiz kabi list bo'sh yoki bo'sh emasligini tekshirishimiz lozim.
Ikkinchisi agar biz yangi nodani head element oldiga qo'shmoqchi bo'lsak add_first() metodigan qayta foydalanib qo'ysak bo'ladi, sababi biz head ni oldiga qo'shmoqchi bo'lsak demak biz shunchaki headni almashtirib qo'ymoqchimiz xolos.
Oxirgisi biz element oldidan element qo'shayotgandan undan oldinda turgan eski elementni (prev_node) bilishimiz shart, sababi yangi qo'shilgan elementni undan orqada qolayotgan elementga next qilib belgilashimiz kerak, ketma ketlik buzilmasligi uchun.
Qimmatbaho namuna ))
>>> llist = LinkedList()
>>> llist.add_before("a", Node("a"))
Exception: List is empty
>>> llist = LinkedList(["b", "c"])
>>> llist
b -> c -> None
>>> llist.add_before("b", Node("a"))
>>> llist
a -> b -> c -> None
>>> llist.add_before("b", Node("aa"))
>>> llist.add_before("c", Node("bb"))
>>> llist
a -> aa -> b -> bb -> c -> None
>>> llist.add_before("n", Node("m"))
Exception: Node with data 'n' not found
Linklangan listga element qo'shish borasida barcha metodlar tayyor.
Linklangan listdan nodani o'chirish
Linklangan listdan element o'chirishda o'chirilishi kerak bo'lgan elementni topish uchun biz avval listni to'liq aylanib chiqishimiz kerak bo'ladi. Kerakli elementni topganimizdan keyin undan bitta oldingi va bitta keyingi elementlarni ulab qo'yamiz.
Bu degani siz Listni traverse qilayotganda izlanayotgan elementdan oldingi nodani track qilishingiz kerak bo'ladi:
1 def remove_node(self, target_node_data):
2 if self.head is None:
3 raise Exception("List is empty")
4
5 if self.head.data == target_node_data:
6 self.head = self.head.next
7 return
8
9 previous_node = self.head
10 for node in self:
11 if node.data == target_node_data:
12 previous_node.next = node.next
13 return
14 previous_node = node
15
16 raise Exception("Node with data '%s' not found" % target_node_data)
Here is an example:
>>> llist = LinkedList()
>>> llist.remove_node("a")
Exception: List is empty
>>> llist = LinkedList(["a", "b", "c", "d", "e"])
>>> llist
a -> b -> c -> d -> e -> None
>>> llist.remove_node("a")
>>> llist
b -> c -> d -> e -> None
>>> llist.remove_node("e")
>>> llist
b -> c -> d -> None
>>> llist.remove_node("c")
>>> llist
b -> d -> None
>>> llist.remove_node("a")
Exception: Node with data 'a' not found
Shu xolos, endi biz linklangan listni implement qilishni bilamiz. Agar biz hozir o'rgangan bilimlarimizni o'zlashtirishga ulgurgan bo'lsak, maslahat berardim quyidagi topshiriqlarni mustaqil bajarishingizga:
- Ma'lum o'rinda turgan elementni olish: llist.get(i) yoki llist[i].
- Linked listni teskari sort qilish yani reverse qilish, llist.reverse()
- LinkedList classdan inherit qiluvchi Queue classini yaratish va shu classda enqueue(), dequeue() metodlarini realizatsiya qiling.
Komplex Linked Listlardan foydalanish
Hozirgacha biz faqat bir tomonlama (singly linked lists) ulangan listnarning tuzilishi va ishlashini o'rgandik. Ammo linked listlarning boshqacha turlari ham mavjud va ular biroz boshqa maqsadlarda ishlatiladi.
Ikki tomonlama ulangan listlar (Doubly linked lists)
Ikki tomonlama ulangan listlarni nodasida ikkita reference bo'ladi:
- Birinchisi Prev yani oldingi elementga
- Ikkinchisi Next yani keyingi elementga reference
Yuqoridagi namunaga biroz o'zgarish kiritib ikki tomonlama ulangan list yasashimiz mumkin:
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.previous = None
Shu yo'l bilan biz listni faqat oldinga emas orqaga qarab ham traverse qilishimiz mumkin, previous reference yordamida.
Sturktura jihatdan ushbu ko'rinishda bo'ladi:
collections.deque linked listlarni sturkturasi ichida ishlatishadi, lekin u ikki tomonlama ulangan listlarni ishlatmaydi. Ikki tomonlama ulangan listlar bilan esa deque istalgan elementni O(1) muddatda o'chirgan bo'lar edi.
Halqasimon ulangan listlar (Circular linked lists)
Halqasimon ulangan listlarda oxirgi elementning next referensi birnchi elementga yani headga qaratilgan bo'ladi, va ushbu ko'rinish tabiikiy halqasimon ko'rinish yasaydi.
Halqasimon ulangan listlarni ajoyib ishlatilish holatlari mavjud:
- Qayta qayta har bir o'yinchiga navbatni berish ko'p o'yinchilar qatnasha oladigan o'yinlarda
- Berilgan operatsion sistemada applicationning life cycle ini boshqarish uchun
- Fibonacci heap yasashda
Ko'rinish jihatdan quyidagicha:
Halqasimon ulangan listlarning bir ustunligi siz bu listni istalgan elementidan boshlab to'liq traverse qilishingiz mukin, faqat traversing boshlangan elementni eslab qolish va shu elementga qaytib kelganda loopni to'xtatish zarur, aks holda checksiz loop hosil bo'ladi.
Halqasimon ulangan listlarni implement qilish unchalik qiyinmas, bitta o'zgarish bu listlarda siz traversing boshlanish nuqtasini o'zingiz bera olasiz:
class CircularLinkedList:
def __init__(self):
self.head = None
def traverse(self, starting_point=None):
if starting_point is None:
starting_point = self.head
node = starting_point
while node is not None and (node.next != starting_point):
yield node
node = node.next
yield node
def print_list(self, starting_point=None):
nodes = []
for node in self.traverse(starting_point):
nodes.append(str(node))
print(" -> ".join(nodes))
Endi listni traverse qilish bittagina argument oladi, starting_point, bu argument biz uchun ham traversingning boshi va oxiri bo'lib xizmat qiladi.
Oxirgi namuna halqasimon listlarni ishlatish namunasi bo'ladi:
>>> circular_llist = CircularLinkedList()
>>> circular_llist.print_list()
None
>>> a = Node("a")
>>> b = Node("b")
>>> c = Node("c")
>>> d = Node("d")
>>> a.next = b
>>> b.next = c
>>> c.next = d
>>> d.next = a
>>> circular_llist.head = a
>>> circular_llist.print_list()
a -> b -> c -> d
>>> circular_llist.print_list(b)
b -> c -> d -> a
>>> circular_llist.print_list(d)
d -> a -> b -> c
Sezgan bo'lsangiz None degan element yo'q, sababi listda oxirgi element degan narsani o'zi yo'q. Keyingi farq biz starting_point ni berganimizda go'yoki butunlay boshqa list hosil bo'layapti )).
O'qib chiqganlar uchun rahmat ! RealPython web sahifasidan tarjima qilindi. Tarjima hechqanaqa adabiy til yoki termin tarjimasiga suyanmagan. Izohlar bo'lsa izohingizni ubaydullo.uz sahifasida xabar sifatida qoldirishingiz mumkin.