- Binary search
- Ternary search
- Jump search
- Exponential search
- Двоично търсене върху функция
- :)
- Едносвързан списък
- Двойносвързан списък
- Вграден списък в Python
Едносвързаният списък представлява поредица от възли, като всеки от тях съдържа информация за данните и кой е следващият възел в поредицата.
Класическата имплементация на възел от едносвързан списък:
class Node:
def __init__(self, data=0, next_=None):
self.data = data
self.next_ = next_
Тази структура може да се обвие в клас, който да представлява свързан списък:
class LinkedList:
def __init__(self, head=None):
self.head = head
Списъкът може да има не само глава, но и опашка:
class LinkedList:
def __init__(self, head=None, tail=None):
self.head = head
self.tail = tail
Опашката дава възможност за добавяне на елемент за константно време в края на списъка:
class LinkedList:
# ...
def push_back(self, data):
new_node = Node(data)
if not self.head:
self.head = self.tail = new_node
else:
self.tail.next_ = new_node
self.tail = new_node
Добавяне на елемент в началото на списъка става за константно време:
class LinkedList:
# ...
def push_front(self, data):
new_node = Node(data)
if not self.head:
self.head = self.tail = new_node
else:
new_node.next_ = self.head
self.head = new_node
Обхождане на свързан списък:
class LinkedList:
# ...
def print(self):
current = self.head
while current:
print(current.data)
current = current.next_
Изтриване на елемент в началото на списъка - константна сложност:
class LinkedList:
# ...
def pop_front(self):
if self.head == self.tail:
self.head = self.tail = None
else:
self.head = self.head.next_
Изтриване на елемент в края на списъка - линейна сложност:
class LinkedList:
# ...
def pop_back(self):
if self.head == self.tail:
self.head = self.tail = None
else:
current = self.head
while current.next_ != self.tail:
current = current.next_
current.next_ = None
self.tail = current
Всеки възел съхранява информация за елемента преди и след себе си. Това позволява обхождане на списъка в обратна посока.
Класическата имплементация на възел от двойносвързан списък:
class Node:
def __init__(self, data, next_=None, prev=None):
self.data = data
self.next_ = next_
self.prev = prev
class DoublyLinkedList:
def __init__(self, head=None, tail=None):
self.head = head
self.tail = tail
Имплементациите на основните функции изискват правилно задаване на предишния елемент за разлика от тези на едносвързан списък.
Добавяне на елемент в началото на списъка - константно време:
class DoublyLinkedList:
# ...
def push_front(self, data):
new_node = Node(data)
if not self.head:
self.head = self.tail = new_node
else:
new_node.next_ = self.head
self.head.prev = new_node
self.head = new_node
Добавяне на елемент в края на списъка - константно време:
class DoublyLinkedList:
# ...
def push_back(self, data):
new_node = Node(data)
if not self.head:
self.head = self.tail = new_node
else:
self.tail.next_ = new_node
new_node.prev = self.tail
self.tail = new_node
Премахване на елемент в началото на списъка - константно време:
class DoublyLinkedList:
# ...
def pop_front(self):
if self.head == self.tail:
self.head = self.tail = None
else:
self.head = self.head.next_
self.head.prev = None
Премахване на елемент в края на списъка - константно време:
class DoublyLinkedList:
# ...
def pop_back(self):
if self.head == self.tail:
self.head = self.tail = None
else:
self.tail = self.tail.prev
self.tail.next_ = None
Получаваме предимството да премахнем последния елемент за константно време, но увеличаваме паметта, нужна за съхранението на структурата.
Предимства на Linked List:
- константно време за добавяне в началото и края.
- константно време за добавяне на елемент на произволна позиция при наличие на указател*.
- не се заделя излишна памет за резервни клетки.
Недостатъци:
- произволен достъп до елемент на дадена позиция не е O(1).*
- заделя се допълнителна памет за всеки указател към следващия елемент.
В Python няма чиста имплементация на свързан списък.
- Интерфейсът на обикновения списък позволява използването му като свързан списък.
- Най-големият недостатък е добавянето на елемент на произволно място в списъка, което е линейна операция.*
llist = [i for i in range(1, 9)]
llist.append(99)
llist.insert(6, 66)
llist # [1, 2, 3, 4, 5, 6, 66, 7, 8, 99]
- Имплементиран е чрез двойносвързан списък на С.
- Интерфейсът му предоставя пълната функционалност на свързания списък при познатите сложности на операциите.
- Допълнително свойство на Deque е достъпването на произволен възел с константа сложност* както при масивите (О(1) random access).
from collections import deque
dlist = deque([1,2,3])
dlist.pop()
dlist.append(33)
dlist.popleft()
dlist.appendleft(-1)
print(dlist) # deque([-1, 2, 33])
print(dlist[1]) # 2
Примерна имплементация на Singly Linked List и Doubly Linked List в playground-а.
Решения на задачите: тук