O(1)
) както в началото, така и в края на списъка. При масивите добавянето в края беше също константна операция, но в началото отнемаше цели O(N)
стъпки.O(1)
можем да добавим елемент и на произволна позиция по средата на списъка, стига вече да имаме указател, сочещ към елемента преди или след тази позиция.O(1)
.int
, то ние ще се нуждаем от поне двойно повече памет. Нашата имплементация ще е двусвързан списък, тоест ще имаме и още един указател към предходния елемент в списъка, което прави нещата дори по-зле в това отношение.DataType
), всяка клетка ще съдържа указател към предходната и следващата клетка в списъка. Ще енкапсулираме тези данни в структура Element
.
typedef int DataType;
struct Element {
DataType data;
Element *prev, *next;
Element(const DataType& value) {
data = value;
prev = next = NULL;
}
};
int
, който да пази общия брой клетки. Забележете, че този брояч реално не ни трябва, но ще го пазим за да можем да изпълняваме метода size()
с O(1)
).
struct List {
int size;
Element *head, *tail;
};
void init(List& list) {
list.size = 0;
list.head = list.tail = NULL;
}
O(1)
. Всъщност не се нуждаем от функция за това (поне при тази имплементация), можем директно да ползваме list.size
в кода си.
int size(List& list) {
return list.size;
}
bool empty(List& list) {
return !list.size;
}
DataType& front(List& list) {
assert(list.size > 0);
return list.head->data;
}
DataType& back(List& list) {
assert(list.size > 0);
return list.tail->data;
}
DataType& at(List& list, int index) {
assert(index >= 0 && index < list.size);
Element* link = list.head;
for (int i = 0; i < index; i++)
link = link->next;
return link->data;
}
void push_front(List& list, const DataType& value) {
Element* element = new Element(value);
element->next = list.head;
if (list.size == 0)
list.head = list.tail = element;
else
list.head = list.head->prev = element;
list.size++;
}
void push_back(List& list, const DataType& value) {
Element* element = new Element(value);
element->prev = list.tail;
if (list.size == 0)
list.head = list.tail = element;
else
list.tail = list.tail->next = element;
list.size++;
}
void insert(List& list, int index, const DataType& value) {
if (index <= 0) {
push_front(list, value);
}
else if (index >= list.size) {
push_back(list, value);
}
else {
Element* link = list.head;
for (int i = 0; i < index - 1; i++)
link = link->next;
Element* element = new Element(value);
element->prev = link;
element->next = link->next;
element->prev->next = element;
element->next->prev = element;
list.size++;
}
}
void pop_front(List& list) {
if (list.size == 0)
return;
if (list.size == 1) {
delete list.head;
list.head = list.tail = NULL;
}
else {
Element* link = list.head;
list.head = link->next;
list.head->prev = NULL;
delete link;
}
list.size--;
}
void pop_back(List& list) {
if (list.size == 0)
return;
if (list.size == 1) {
delete list.head;
list.head = list.tail = NULL;
}
else {
Element* link = list.tail;
list.tail = link->prev;
list.tail->next = NULL;
delete link;
}
list.size--;
}
void erase(List& list, int first, int last) {
first = (first < 0 ? 0 : first);
int count = (last == -1 ? 1 : last - first);
if (first >= list.size || count <= 0)
return;
Element* link = list.head;
for (int i = 0; i < first; i++)
link = link->next;
for (int i = 0; i < count && link != NULL; i++) {
if (list.head == link)
list.head = link->next;
if (list.tail == link)
list.tail = link->prev;
if (link->prev != NULL)
link->prev->next = link->next;
if (link->next != NULL)
link->next->prev = link->prev;
Element* next = link->next;
delete link;
link = next;
list.size--;
}
}
erase()
-нем от първия до последния елемент, което и всъщност ще направим за да не пишем кода наново.
void clear(List& list) {
while (list.head != NULL) {
Element* element = list.head;
list.head = list.head->next;
delete element;
}
list.size = 0;
list.head = list.tail = NULL;
}
Selected text (if you see this, there is something wrong)
(Незадължително) E-mail за обратна връзка: