W klasie DoubleList przechowujemy łącza do początku i do końca listy oraz dla wygody zapamiętujemy liczbę elementów przechowywanych w liście.
class Node: """Klasa reprezentująca węzeł listy dwukierunkowej.""" def __init__(self, data=None, next=None, prev=None): self.data = data self.next = next self.prev = prev def __str__(self): return str(self.data) def __eq__(self, other): return self.data == other.data def __ne__(self, other): return not self == other
class DoubleList: """Klasa reprezentująca całą listę dwukierunkową.""" def __init__(self): self.length = 0 self.head = None self.tail = None def is_empty(self): #return self.length == 0 return self.head is None def count(self): return self.length def insert_head(self, node): if self.head: node.next = self.head self.head.prev = node # stary head self.head = node # nowy head else: # pusta lista self.head = node self.tail = node self.length += 1 def insert_tail(self, node): if self.tail: node.prev = self.tail self.tail.next = node # stary tail self.tail = node # nowy tail else: # pusta lista self.head = node self.tail = node self.length += 1 def remove_head(self): # zwraca node if self.is_empty(): raise ValueError("pusta lista") elif self.head is self.tail: # length == 1 node = self.head self.head = None self.tail = None self.length = 0 return node else: node = self.head self.head = self.head.next self.head.prev = None # czyszczenie node.next = None # czyszczenie self.length -= 1 return node def remove_tail(self): # zwraca node if self.is_empty(): raise ValueError("pusta lista") elif self.head is self.tail: # length == 1 node = self.tail self.head = None self.tail = None self.length = 0 return node else: node = self.tail self.tail = self.tail.prev self.tail.next = None # czyszczenie node.prev = None self.length -= 1 return node
Listę powiązaną podwójnie można wydajnie przechodzić w obu kierunkach. Warto stworzyć odpowiednie iteratory. Nie należy zmieniać zawartości listy podczas iterowania po niej.
class DoubleList: # ... inne metody ... def __iter__(self): # wykorzystanie funkcji generatora node = self.head while node: yield node.data node = node.next def __reversed__(self): # wykorzystanie funkcji generatora node = self.tail while node: yield node.data node = node.prev
# Zastosowanie. alist = DoubleList() alist.insert_head(Node(11)) # [11] alist.insert_head(Node(22)) # [22, 11] alist.insert_tail(Node(33)) # [22, 11, 33] for item in alist: # kolejność 22, 11, 33 print(item) for item in reversed(alist): # kolejność 33, 11, 22 print(item)