Skip to content

Commit

Permalink
完善20.4节双向链表v4,支持不可默认构造的元素类型
Browse files Browse the repository at this point in the history
  • Loading branch information
ZZy979 committed Feb 15, 2024
1 parent d649744 commit d08265f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Print CMake Version
run: cmake --version
- name: Configure CMake
Expand Down
53 changes: 27 additions & 26 deletions ch20/doubly_linked_list_v4.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,36 @@
#include <iterator>
#include <type_traits>

// doubly-linked list node
template<class T>
struct Link {
Link* prev; // previous link
Link* succ; // successor (next) link
T val; // the value
struct Node_base {
Node_base* prev; // previous link
Node_base* succ; // successor (next) link

void insert(Link* n);
void insert(Node_base* n);
void erase();
};

// insert n before this node
template<class T>
void Link<T>::insert(Link* n) {
void Node_base::insert(Node_base* n) {
n->succ = this;
n->prev = prev;
if (prev) prev->succ = n;
prev = n;
}

// remove this node from list
template<class T>
void Link<T>::erase() {
void Node_base::erase() {
if (succ) succ->prev = prev;
if (prev) prev->succ = succ;
}

// doubly-linked list node
template<class T>
struct Link : public Node_base {
T val; // the value

explicit Link(const T& v = T()) :Node_base{}, val(v) {}
};

// doubly-linked list iterator
template<class T>
struct List_iterator {
Expand All @@ -40,18 +43,18 @@ struct List_iterator {
using pointer = T*;
using reference = T&;

explicit List_iterator(Link<T>* p) :node(p) {}
explicit List_iterator(Node_base* p) :node(p) {}

List_iterator& operator++() { node = node->succ; return *this; } // forward
List_iterator& operator--() { node = node->prev; return *this; } // backward

T& operator*() { return node->val; } // get value (dereference)
T* operator->() { return &node->val; }
T& operator*() { return static_cast<Link<T>*>(node)->val; } // get value (dereference)
T* operator->() { return &static_cast<Link<T>*>(node)->val; }

bool operator==(const List_iterator& b) const { return node == b.node; }
bool operator!=(const List_iterator& b) const { return node != b.node; }

Link<T>* node; // current link
Node_base* node; // current link
};

// doubly-linked list
Expand Down Expand Up @@ -106,27 +109,25 @@ class list {
void pop_back() { erase(iterator(head.prev)); }

// the first element
T& front() { return head.succ->val; }
T& front() { return *begin(); }

// the last element
T& back() { return head.prev->val; }
T& back() { return *std::prev(end()); }

int size() const { return sz; }

private:
void _init();
void _clear();

// TODO 头节点val不初始化
Link<T> head; // virtual head node
Node_base head; // virtual head node
int sz; // number of elements
};

// insert v into list before p
template<class T>
typename list<T>::iterator list<T>::insert(iterator p, const T& v) {
Link<T>* tmp = new Link<T>;
tmp->val = v;
auto tmp = new Link<T>(v);
p.node->insert(tmp);
++sz;
return iterator(tmp);
Expand All @@ -136,9 +137,9 @@ typename list<T>::iterator list<T>::insert(iterator p, const T& v) {
template<class T>
typename list<T>::iterator list<T>::erase(iterator p) {
if (p == end()) return p;
Link<T>* next = p.node->succ;
auto next = p.node->succ;
p.node->erase();
delete p.node;
delete static_cast<Link<T>*>(p.node);
--sz;
return iterator(next);
}
Expand All @@ -151,10 +152,10 @@ void list<T>::_init() {

template<class T>
void list<T>::_clear() {
Link<T>* p = head.succ;
auto p = head.succ;
while (p != &head) {
Link<T>* next = p->succ;
delete p;
auto next = p->succ;
delete static_cast<Link<T>*>(p);
p = next;
}
}
49 changes: 28 additions & 21 deletions ch20/doubly_linked_list_v4_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ class DoublyLinkedListV4Test : public ::testing::Test {
list<double> l_ = {0.0, 1.1, 2.2, 3.3, 4.4};
};

// for testing list of class without default
struct No_default {
No_default(int) {}
};

TEST_F(DoublyLinkedListV4Test, DefaultConstructor) {
list<double> l;
EXPECT_EQ(l.size(), 0);
Expand All @@ -25,11 +30,13 @@ TEST_F(DoublyLinkedListV4Test, Constructor) {
for (int i : li)
EXPECT_EQ(i, 8);

// TODO class without default
// class without default
list<No_default> ln(10, No_default(8));
EXPECT_EQ(ln.size(), 10);

// class with resources
list<Counted_element> le(10);
EXPECT_EQ(Counted_element::count(), 11);
EXPECT_EQ(Counted_element::count(), 10);
}

TEST_F(DoublyLinkedListV4Test, InitializerListConstructor) {
Expand All @@ -39,14 +46,14 @@ TEST_F(DoublyLinkedListV4Test, InitializerListConstructor) {
EXPECT_TRUE(std::equal(ld.begin(), ld.end(), expected));

// class with resources
list<Counted_element> ve = {Counted_element(), Counted_element(), Counted_element()};
EXPECT_EQ(Counted_element::count(), 4);
list<Counted_element> le = {Counted_element(), Counted_element(), Counted_element()};
EXPECT_EQ(Counted_element::count(), 3);
}

TEST_F(DoublyLinkedListV4Test, Destructor) {
// class with resources
auto ple = new list<Counted_element>(8);
EXPECT_EQ(Counted_element::count(), 9);
EXPECT_EQ(Counted_element::count(), 8);
delete ple;
EXPECT_EQ(Counted_element::count(), 0);
}
Expand Down Expand Up @@ -94,9 +101,9 @@ TEST_F(DoublyLinkedListV4Test, Insert) {

// class with resources
list<Counted_element> le(5);
EXPECT_EQ(Counted_element::count(), 6);
EXPECT_EQ(Counted_element::count(), 5);
le.insert(std::next(le.begin(), 2), Counted_element());
EXPECT_EQ(Counted_element::count(), 7);
EXPECT_EQ(Counted_element::count(), 6);
}

TEST_F(DoublyLinkedListV4Test, Erase) {
Expand Down Expand Up @@ -127,9 +134,9 @@ TEST_F(DoublyLinkedListV4Test, Erase) {

// class with resources
list<Counted_element> le(5);
EXPECT_EQ(Counted_element::count(), 6);
le.erase(std::next(le.begin(), 2));
EXPECT_EQ(Counted_element::count(), 5);
le.erase(std::next(le.begin(), 2));
EXPECT_EQ(Counted_element::count(), 4);
}

TEST_F(DoublyLinkedListV4Test, Clear) {
Expand All @@ -143,10 +150,10 @@ TEST_F(DoublyLinkedListV4Test, Clear) {
EXPECT_EQ(l_.size(), 0);

// class with resources
list<Counted_element> ve(5);
EXPECT_EQ(Counted_element::count(), 6);
ve.clear();
EXPECT_EQ(Counted_element::count(), 1);
list<Counted_element> le(5);
EXPECT_EQ(Counted_element::count(), 5);
le.clear();
EXPECT_EQ(Counted_element::count(), 0);
}

TEST_F(DoublyLinkedListV4Test, PushBack) {
Expand All @@ -163,9 +170,9 @@ TEST_F(DoublyLinkedListV4Test, PushBack) {

// class with resources
list<Counted_element> le(5);
EXPECT_EQ(Counted_element::count(), 6);
EXPECT_EQ(Counted_element::count(), 5);
le.push_back(Counted_element());
EXPECT_EQ(Counted_element::count(), 7);
EXPECT_EQ(Counted_element::count(), 6);
}

TEST_F(DoublyLinkedListV4Test, PopBack) {
Expand All @@ -174,9 +181,9 @@ TEST_F(DoublyLinkedListV4Test, PopBack) {

// class with resources
list<Counted_element> le(5);
EXPECT_EQ(Counted_element::count(), 6);
le.pop_back();
EXPECT_EQ(Counted_element::count(), 5);
le.pop_back();
EXPECT_EQ(Counted_element::count(), 4);
}

TEST_F(DoublyLinkedListV4Test, PushFront) {
Expand All @@ -193,9 +200,9 @@ TEST_F(DoublyLinkedListV4Test, PushFront) {

// class with resources
list<Counted_element> le(5);
EXPECT_EQ(Counted_element::count(), 6);
EXPECT_EQ(Counted_element::count(), 5);
le.push_front(Counted_element());
EXPECT_EQ(Counted_element::count(), 7);
EXPECT_EQ(Counted_element::count(), 6);
}

TEST_F(DoublyLinkedListV4Test, PopFront) {
Expand All @@ -204,7 +211,7 @@ TEST_F(DoublyLinkedListV4Test, PopFront) {

// class with resources
list<Counted_element> le(5);
EXPECT_EQ(Counted_element::count(), 6);
le.pop_front();
EXPECT_EQ(Counted_element::count(), 5);
le.pop_front();
EXPECT_EQ(Counted_element::count(), 4);
}

0 comments on commit d08265f

Please sign in to comment.