6. 帶哨兵的單向迴圈連結串列
阿新 • • 發佈:2018-12-25
- 《演算法導論》10.2-5 使用單向迴圈連結串列實現字典操作 INSERT、DELETE、SEARCH,並給出執行時間。
#include <iostream> #include <string.h> template<typename Object> class SingleLinkedList { public: SingleLinkedList() { init(); } SingleLinkedList(const SingleLinkedList& rhs) { init(); for(Node* p = rhs.sentinel->next; p != rhs.sentinel; p = p->next)//Error Note: ++p push_back(p->object); } SingleLinkedList(SingleLinkedList&& rhs) { sentinel = rhs.sentinel; sentinelPrev = rhs.sentinelPrev; rhs.sentinel = rhs.sentinelPrev = nullptr; } SingleLinkedList& operator =(const SingleLinkedList& rhs) { auto copy(rhs); std::swap(copy.sentinel, this->sentinel); std::swap(copy.sentinelPrev, this->sentinelPrev); return *this; } SingleLinkedList& operator =(SingleLinkedList&& rhs) { std::swap(rhs.sentinel, this->sentinel); std::swap(rhs.sentinelPrev, this->sentinelPrev); return *this; } ~SingleLinkedList() { if(sentinel) { while(!empty()) pop_front(); delete sentinel; sentinel = sentinelPrev = nullptr; } } //push操作的執行時間都是O(1) void push_back(const Object& object) { Node* pNew = new Node{object, sentinel}; sentinelPrev->next = pNew; sentinelPrev = pNew; } void push_back(Object&& object) { Node* pNew = new Node{std::move(object), sentinel}; sentinelPrev->next = pNew; sentinelPrev = pNew; } void push_front(const Object& object) { Node* pNew = new Node{object, sentinel->next}; if(empty()) sentinelPrev = pNew; sentinel->next = pNew; } void push_front(Object&& object) { Node* pNew = new Node{std::move(object), sentinel->next}; if(empty()) sentinelPrev = pNew; sentinel->next = pNew; } void pop_front() { if(!empty()) erase(sentinel); } void erase(const Object& object) { Node* prev = findPrev(object); if(prev) erase(prev); } Object* find(const Object& object) //執行時間O(n) { Node* prev = findPrev(object); if(prev) return &(prev->next->object); else return nullptr; } const Object* find(const Object &object) const { const Node* prev = findPrev(object); if(prev) return &(prev->next->object); else return nullptr; } bool empty()const{ return sentinelPrev == sentinel;} private: struct Node { Object object; Node* next; }; Node* sentinel; Node* sentinelPrev; void init() { sentinel = new Node; sentinel->next = sentinelPrev = sentinel; } //刪除p的後繼節點, 執行時間O(1) void erase(Node* p) { auto pDelete = p->next; p->next = pDelete->next; if(p->next == sentinel) sentinelPrev = p; delete pDelete; //Error Note: delete p->next; pDelete should be used } const Node* findPrev(const Object& object) const { for(const Node *prev = sentinel, *current = sentinel->next; current != sentinel; prev = current, current = current->next) { if(current->object == object) return prev; } return nullptr;//Error Note: forgotten } Node* findPrev(const Object& object) { for(Node *prev = sentinel, *current = sentinel->next; current != sentinel; prev = current, current = current->next) { if(current->object == object) return prev; } return nullptr; } }; void testSingleLinkedList() { using namespace std; struct Student { const char* name; int age; bool operator ==(const Student& rhs) const { return 0 == strcmp(name, rhs.name) && age == rhs.age; } }; constexpr int NUM = 5; Student students[NUM] = {Student{"Tom", 12},Student{"Micheal", 13}, Student{"Anna", 14},Student{"Lily", 10}, Student{"James", 19}}; SingleLinkedList<Student> sl; sl.push_back(students[0]); sl.push_back(students[1]); sl.push_back(Student{"Anna", 14}); sl.push_front(students[3]); sl.push_front(students[4]); Student* tom = sl.find(students[0]); tom->age = 20; tom = sl.find(students[0]); if(tom == nullptr) cout << "cannot find {Tom, 12}" << endl; students[0].age = 20; sl.pop_front(); sl.erase(students[3]); sl.erase(students[1]); sl.erase(students[2]); tom = sl.find(students[0]); cout << tom->age << endl; const decltype(sl) sl_copy(sl); const Student* tom1 = sl_copy.find(students[0]); cout << tom1->age << endl; decltype(sl) sl_move(sl); tom = sl_move.find(students[0]); cout << tom->age << endl; sl_move = sl_copy; tom = sl_move.find(students[0]); cout << tom->age << endl; } /*test output: cannot find {Tom, 12} 20 20 20 20*/