diff --git a/lectures/list/double_linked_list.hpp b/lectures/list/double_linked_list.hpp index a08909d..836ed91 100644 --- a/lectures/list/double_linked_list.hpp +++ b/lectures/list/double_linked_list.hpp @@ -1,5 +1,6 @@ #ifndef DOUBLE_LINKED_LIST_HPP #define DOUBLE_LINKED_LIST_HPP + #include #include @@ -100,6 +101,71 @@ class DoubleLinkedList { deleteFirst(front->data); } + void split(I& list, I& left, I& right) { + if(!list.valid()) { + left = right = I(); + return; + } + + if(!list.next().valid()) { + left = list; + right = I(); + return; + } + + I slow = list; + I fast = list; + + while(fast.valid() && fast.next().valid()) { + fast = fast.next().next(); + if(fast.valid()) + slow = slow.next(); + } + + left = list; + right = slow.next(); + slow.ptr->next->prev = nullptr; + slow.ptr->next = nullptr; + } + + I merge(I left, I right) { + if(!left.valid()) + return right; + + if(!right.valid()) + return left; + + if(left.get() <= right.get()) { + I recResult = merge(left.next(), right); + left.ptr->next = recResult.ptr; + recResult.ptr->prev = left.ptr; + return left; + } else { + I recResult = merge(left, right.next()); + right.ptr->next = recResult.ptr; + recResult.ptr->prev = right.ptr; + return right; + } + } + + I mergeSort(I list) { + if(!list.valid()) { + return I(); + } + + if(!list.next().valid()) { + return list; + } + + I left = I(), right = I(); + + split(list, left, right); + left = mergeSort(left); + right = mergeSort(right); + + return merge(left, right); + } + public: using Iterator = I; @@ -266,6 +332,40 @@ class DoubleLinkedList { // it1.prev() = it2 -- добър случай, четна дължина return *it1 == *it2; } + + // Обръща списъка in place + // O(n) по време, О(1) по памет + void reverse() { + if (empty() || front == back) return; + + I prevEl = nullptr; + I currEl = front; + I nextEl = nullptr; + + back = front; + + while (currEl != nullptr) { + nextEl = currEl.next(); + + currEl.ptr->next = prevEl.ptr; + currEl.ptr->prev = nextEl.ptr; + + prevEl = currEl; + currEl = nextEl; + } + + front = prevEl.ptr; + } + + void sort() { + front = mergeSort(begin()).ptr; + + I it = begin(); + while(it && it.next().valid()) + it = it.next(); + + back = it.ptr; + } }; #endif // DOUBLE_LINKED_LIST_HPP \ No newline at end of file diff --git a/lectures/list/linked_list.hpp b/lectures/list/linked_list.hpp index 680bec0..deec0a2 100644 --- a/lectures/list/linked_list.hpp +++ b/lectures/list/linked_list.hpp @@ -1,5 +1,6 @@ #ifndef LINKED_LIST_HPP #define LINKED_LIST_HPP + #include #include @@ -94,6 +95,62 @@ class LinkedList { deleteFirst(front->data); } + void split(I list, I& left, I& right) { + if(!list.valid()) { + left = right = I(); + return; + } + + if(!list.next().valid()) { + left = list; + right = I(); + return; + } + + I slow = list; + I fast = list; + + while(fast.valid() && fast.next().valid()) { + fast = fast.next().next(); + if(fast.valid()) + slow = slow.next(); + } + + left = list; + right = slow.next(); + slow.ptr->next = nullptr; + } + + I merge(I left, I right) { + if(!left.valid()) + return right; + + if(!right.valid()) + return left; + + if(left.get() <= right.get()) { + left.ptr->next = merge(left.next(), right).ptr; + return left; + } else { + right.ptr->next = merge(left, right.next()).ptr; + return right; + } + } + + I mergeSort(I list) { + if(!list.valid() || !list.next().valid()) { + return list; + } + + I left = I(), right = I(); + + split(list, left, right); + left = mergeSort(left); + right = mergeSort(right); + + return merge(left, right); + } + public: using Iterator = I; @@ -240,6 +297,38 @@ class LinkedList { } } + // Обръща списъка in place + // O(n) по време, О(1) по памет + void reverse() { + if (empty() || front == back) return; + + I prev = nullptr; + I curr = front; + I next = nullptr; + + back = front; + + while (curr != nullptr) { + next = curr.next(); + + curr.ptr->next = prev.ptr; + + prev = curr; + curr = next; + } + + front = prev.ptr; + } + + void sort() { + front = mergeSort(begin()).ptr; + + I it = begin(); + while(it && it.next().valid()) + it = it.next(); + + back = it.ptr; + } }; #endif // LINKED_LIST_HPP \ No newline at end of file diff --git a/lectures/list/list_tests.hpp b/lectures/list/list_tests.hpp index f026511..4d694a4 100644 --- a/lectures/list/list_tests.hpp +++ b/lectures/list/list_tests.hpp @@ -376,3 +376,71 @@ TEST_CASE("Списък с 2 елемента не е палиндром, ако CHECK(list.insertLast(2)); CHECK(!list.isPalindrome()); } + + +TEST_CASE_TEMPLATE("Обръщане на празен списък без заделяне на нова памет", SomeList, LISTS) { + SomeList list; + list.reverse(); + CHECK(list.empty()); +} + +TEST_CASE_TEMPLATE("Обръщане на списък с 1 елемент без заделяне на нова памет", SomeList, LISTS) { + const unsigned val = 42; + SomeList list; + + list.insertFirst(val); + list.reverse(); + + CHECK(!list.empty()); + CHECK_EQ(list.begin().get(), val); +} + +TEST_CASE_TEMPLATE("Обръщане на списък с числата от 1 до 10 без заделяне на нова памет", SomeList, LISTS) { + SomeList list; + for (int i = 1; i <= 10; i++) + CHECK(list.insertLast(i)); + + list.reverse(); + + int i = 10; + for (int j : list) + CHECK(j == i--); + CHECK(i == 0); +} + +TEST_CASE_TEMPLATE("Сортиране на непразен списък с числата от 1 до 10 в разбъркан ред", SomeList, LISTS) { + SomeList list; + CHECK(list.insertLast(5)); + CHECK(list.insertLast(3)); + CHECK(list.insertLast(7)); + CHECK(list.insertLast(1)); + CHECK(list.insertLast(10)); + CHECK(list.insertLast(2)); + CHECK(list.insertLast(9)); + CHECK(list.insertLast(4)); + CHECK(list.insertLast(6)); + CHECK(list.insertLast(8)); + + list.sort(); + + int i = 1; + for (int j : list) + CHECK_EQ(i++, j); + CHECK_EQ(i, 11); +} + +TEST_CASE_TEMPLATE("Сортиране на празен списък", SomeList, LISTS) { + SomeList list; + list.sort(); + CHECK(list.empty()); +} + +TEST_CASE_TEMPLATE("Сортиране на списък с 1 елемент", SomeList, LISTS) { + SomeList list; + CHECK(list.insertLast(42)); + + list.sort(); + + CHECK_EQ(*list.begin(), 42); + CHECK_EQ(list.begin().next(), list.end()); +} \ No newline at end of file