diff --git a/thu_dsa/chp3/List.h b/thu_dsa/chp3/List.h new file mode 100644 index 0000000..67ad565 --- /dev/null +++ b/thu_dsa/chp3/List.h @@ -0,0 +1,221 @@ +#ifndef LIST_H_ +#define LIST_H_ + +#include "ListNode.h" + +template +class List{ +private: + ListNodePosi(T) head; + ListNodePosi(T) tail; + int size; + +protected:// internal methods + + +public: + //constructors + List(); // empty List + List(List const &L); // copy from another List + List(List const &L, int rank, int n); // copy n elements from L[rank] + List(ListNodePosi(T) p, int n); // copy n elements from position p + + //deconstructor + ~List(); + + //read-only interfaces + ListNodePosi(T) first() const { return head->succ; } + ListNodePosi(T) last() const { return tail->prev; } + ListNodePosi(T) find(T const &val) const { return find(val, size, tail); } //find val from all elements of the list + ListNodePosi(T) find(T const &val, int n, ListNodePosi(T) p) const; //find val from a range of n elements before p + T& operator[](int rank); + int getSize() const { return size; } + bool empty() const { return size == 0; } + + //writable interfaces + + //insert and delete operations + ListNodePosi(T) push_back(T const &val); + ListNodePosi(T) push_front(T const & val); + ListNodePosi(T) insert_before(int rank, T const &val); + ListNodePosi(T) insert_before(ListNodePosi(T) p, T const &val); + ListNodePosi(T) pop_back(); + ListNodePosi(T) pop_front(); + ListNodePosi(T) pop(int rank); + ListNodePosi(T) pop(ListNodePosi(T) p); + + //deduplicate & uniquify + int deduplicate(); + int uniquify(); +}; + +/*----------implementations of class List----------*/ + +//constructors +template +List::List(){ + tail = new ListNode(); + head = new ListNode(); + tail->prev = head; + head->succ = tail; + size = 0; +} + +template +List::List(List const &L) { + tail = new ListNode(); + head = new ListNode(); + tail->prev = head; + head->succ = tail; + size = 0; + + ListNodePosi(T) p = L.head->succ; + for (int ix = 0, size = L.getSize(); ix != size; ++ix, p = p->succ) + push_back(p->val); +} + +template +List::List(List const &L, int rank, int n){ + ListNodePosi(T) p = L.head->succ; + while (rank--) p = p->succ; + + tail = new ListNode(); + head = new ListNode(); + tail->prev = head; + head->succ = tail; + size = 0; + + for (int ix = 0; ix != n; ++ix, p = p->succ) + push_back(p->val); +} + +template +List::List(ListNodePosi(T) p, int n){ + tail = new ListNode(); + head = new ListNode(); + tail->prev = head; + head->succ = tail; + size = 0; + + for (int ix = 0; ix != n; ++ix, p = p->succ) + push_back(p->val); +} + +//deconstructor +template +List::~List(){ + while (size) pop_back(); +} + +//read-only interfaces + +template +ListNodePosi(T) List::find(T const &val, int n, ListNodePosi(T) p) const { + while ((p = p->prev) != head && n--) + if (p->val == val) return p; + return nullptr; +} + +template +T& List::operator[](int rank){ + ListNodePosi(T) p = head->succ; + while (rank--) p = p->succ; + return p->val; +} + +// writable interfaces + +//insert and delete operations +template +ListNodePosi(T) List::push_back(T const &val){ + ++size; + return tail->insertAsPred(val); +} + +template +ListNodePosi(T) List::push_front(T const &val) { + ++size; + return head->insertAsSucc(val); +} + +template +ListNodePosi(T) List::pop_back() { + if (empty()) return nullptr; + + ListNodePosi(T) res = tail->prev; + res->prev->succ = tail; + tail->prev = res->prev; + --size; + return res; +} + +template +ListNodePosi(T) List::pop_front() { + if (empty()) return nullptr; + + ListNodePosi(T) res = head->succ; + head->succ = res->succ; + res->succ->prev = head; + --size; + return res; +} + +template +ListNodePosi(T) List::insert_before(int rank, T const &val){ + ListNodePosi(T) p = head->succ; + while (rank--) p = p->succ; + return insert_before(p, val); +} + +template +ListNodePosi(T) List::insert_before(ListNodePosi(T) p, T const &val){ + ++size; + return p->insertAsPred(val); +} + +template +ListNodePosi(T) List::pop(int rank){ + if (rank >= size || rank < 0) return nullptr; + + ListNodePosi(T) p = head->succ; + while (rank--) p = p->succ; + return pop(p); +} + +template +ListNodePosi(T) List::pop(ListNodePosi(T) p){ + p->prev->succ = p->succ; + p->succ->prev = p->prev; + --size; + return p; +} + +//deduplicate & uniquify +template +int List::deduplicate(){ + int oldSize = size; + ListNodePosi(T) p = head->succ; + ListNodePosi(T) tmp; + for (; p != tail; p = p->succ){ + for(tmp = head->succ; tmp != p; tmp = tmp->succ){ + if(tmp->val == p->val){ + pop(tmp); + break; + } + } + } + return oldSize - size; +} + +template +int List::uniquify(){ + if (empty()) return 0; + + int oldSize = size; + ListNodePosi(T) p = head->succ; + while ((p = p->succ) != tail) + if (p->val == p->prev->val) pop(p); + return oldSize - size; +} + +#endif diff --git a/thu_dsa/chp3/ListNode.h b/thu_dsa/chp3/ListNode.h new file mode 100644 index 0000000..f06a9b6 --- /dev/null +++ b/thu_dsa/chp3/ListNode.h @@ -0,0 +1,55 @@ +#ifndef LISTNODE_H_ +#define LISTNODE_H_ + +#define ListNodePosi(T) ListNode* + +template +class ListNode{ +public: + ListNodePosi(T) prev; + ListNodePosi(T) succ; + T val; + + //constructor + ListNode(); + ListNode(T val, ListNodePosi(T) const &p = nullptr, ListNodePosi(T) const &s = nullptr); + + //external interfaces + ListNodePosi(T) insertAsPred(T const &val); + ListNodePosi(T) insertAsSucc(T const &val); +}; + +/*----------implementation of class ListNode----------*/ + +//constructor +template +ListNode::ListNode(){ + prev = nullptr; + succ = nullptr; +} + +template +ListNode::ListNode( T v, ListNodePosi(T) const &p = nullptr, ListNodePosi(T) const &s = nullptr ){ + val = v; + prev = p; + succ = s; +} + +//external interfaces +template +ListNodePosi(T) ListNode::insertAsPred(T const &val){ + ListNodePosi(T) newNode = new ListNode(val, prev, this); + prev->succ = newNode; + prev = newNode; + return newNode; +} + +template +ListNodePosi(T) ListNode::insertAsSucc(T const &val){ + ListNodePosi(T) newNode = new ListNode(val, this, succ); + succ->prev = newNode; + succ = newNode; + return newNode; +} + +#endif diff --git a/thu_dsa/chp3/test_list.cpp b/thu_dsa/chp3/test_list.cpp new file mode 100644 index 0000000..6439d3a --- /dev/null +++ b/thu_dsa/chp3/test_list.cpp @@ -0,0 +1,142 @@ +#include "List.h" +#include +#include +using std::cout; +using std::endl; + +void test_constructor1(); +void test_constructor2(); +void test_push(); +void test_pop(); +void test_find(); +void test_deduplicate(); +void test_uniquify(); + +int main(){ + cout << "Running tests......" << endl; + test_constructor1(); + test_constructor2(); + test_push(); + test_pop(); + test_find(); + test_deduplicate(); + test_uniquify(); + + cout << "All tests passed." << endl; + system("pause"); + return 0; +} + +void test_constructor1(){ + List l; + assert(l.getSize() == 0); + assert(l.empty()); +} + +void test_constructor2(){ + List l1; + int i[] = { 5,6,8,9,7,3,4,1,2,0 }; + for (int ix = 0; ix != 10; ix++) + l1.push_back(i[ix]); + + List l2(l1); + for (int ix = 0; ix != 10; ix++) + assert(l2[ix] == i[ix]); + + List l4(l1.first(), 5); + for (int ix = 0; ix != 5; ix++) + assert(l4[ix] == i[ix]); + assert(l4.getSize() == 5); + + List l5(l1.last(), 1); + assert(l5.getSize() == 1); + assert(l5.first()->val == 0); + + List l3(l1, 3, 6); + assert(l3.getSize() == 6); + for (int ix = 0; ix != 6; ix++) + assert(l3[ix] == i[3+ix]); +} + +void test_push(){ + List l; + double d[] = { 1.2, 3.4, 5.6, 7.8, 9.0 }; + for (int ix = 0; ix != 5; ix++) + l.push_back(d[ix]); + for (int ix = 0; ix != 5; ix++) + assert(l[ix] == d[ix]); + + List l1; + int i[] = { 5,6,8,9,7,3,4,1,2,0 }; + for (int ix = 0; ix != 10; ix++) + l1.push_front(i[ix]); + for (int ix = 0; ix != 10; ix++) + assert(l1[ix] == i[9-ix]); + + //test insert_before + assert(l1.insert_before(0, 12)->val == 12); + assert(l1.getSize() == 11); + assert(l1.insert_before(11, 14)->val == 14); + assert(l1.getSize() == 12); +} + +void test_pop(){ + List l1; + int i[] = { 5,6,8,9,7,3,4,1,2,0 }; + for (int ix = 0; ix != 10; ix++) + l1.push_back(i[ix]); + + assert(l1.pop_back()->val == 0); + assert(l1.pop_back()->val == 2); + assert(l1.pop_front()->val == 5); + assert(l1.pop_front()->val == 6); + assert(l1.getSize() == 6); + + assert(l1.pop(3)->val == 3); + assert(l1.pop(5) == nullptr); + ListNodePosi(int) p = l1.first(); + assert(l1.pop(p)->val == 8); +} + +void test_find(){ + List l1; + int i[] = { 5,6,8,9,7,3,4,1,2,0 }; + for (int ix = 0; ix != 10; ix++) + l1.push_back(i[ix]); + + assert(l1.find(8)->val == 8); + assert(l1.find(7)->val == 7); + assert(l1.find(12) == nullptr); + + assert(l1.find(7, 5, l1.last())->val == 7); + assert(l1.find(7, 4, l1.last()) == nullptr); +} + +void test_deduplicate(){ + List l1; + int i[] = { 5,6,8,9,7,3,4,1,2,0}; + for (int ix = 0; ix != 10; ix++) { + l1.push_front(i[ix]); + l1.push_back(i[ix]); + } + + assert(l1.getSize() == 20); + assert(l1.deduplicate() == 10); + assert(l1.getSize() == 10); + for (int ix = 0; ix != 10; ix++) + assert(l1[ix] == i[ix]); +} + +void test_uniquify(){ + List l1; + int i[] = {5,8,12,14,15,19,20,22,29,36}; + for (int ix = 0; ix != 11; ix++) { + l1.push_back(i[ix]); + l1.push_back(i[ix]); + } + + assert(l1.getSize() == 22); + assert(l1.uniquify() == 11); + for (int ix = 0; ix != 11; ix++) + assert(l1[ix] == i[ix]); +}