雙向鏈表的操作特點:
(1) “查詢” 和單鏈表相同;
(2)“插入” 和“刪除”時需要同時修改兩個方向上的指針。
但是對於雙向循環鏈表則在表尾插入非常的迅速, 只需O(1)的時間,因為有指向前面的指針, 因此雙向循環鏈表會很容易的找到位於表尾的元素,因此雙向循環鏈表比較適用於頻繁在表尾插入的情況.
空鏈表:
雙向循環鏈表節點構造:
class DoubleListNode { private: Type data; DoubleListNode *prev; //前向指針域 DoubleListNode *next; //後項指針域 };
因為需要將其用於DoubleList類,因此需要將其改造如下:
templateclass DoubleListNode { //友元聲明 friend class DoubleList ; friend class ListIterator ; template friend ostream &operator<<(ostream &os, const DoubleList &list); private: DoubleListNode(const Type &dataValue) :data(dataValue),prev(NULL),next(NULL) {} Type data; DoubleListNode *prev; //前向指針域 DoubleListNode *next; //後項指針域 };
雙向循環鏈表構造:
templateclass DoubleList { friend class ListIterator ; template friend ostream &operator<<(ostream &os, const DoubleList &list); public: DoubleList(); ~DoubleList(); void push_back(const Type &data); void push_front(const Type &data); void insert(int position, const Type &data); void pop_front(); void pop_back(); void remove(const Type &removeData); bool search(const Type &searchData) const; bool isEmpty() const { return (first->next == first); } private: //將節點x插入到節點previous後面 void insertPrivate(DoubleListNode *previous, DoubleListNode *x); void removePrivate(DoubleListNode *x); private: DoubleListNode *first; };
鏈表的構造與析構:
//構造鏈表 templateDoubleList ::DoubleList() { first = new DoubleListNode (0); first->next = first; first->prev = first; }
//析構鏈表 templateDoubleList ::~DoubleList() { DoubleListNode *deleteNode = NULL; //保存鏈表尾元素 DoubleListNode *tmp = first; //first首先指向第一個真實的元素 first = first->next; //一路到達鏈表結尾 while (first != tmp) { deleteNode = first; first = first -> next; delete deleteNode; } // 釋放掉鏈表的空節點(表頭) delete tmp; }
鏈表元素插入與刪除的兩大主力:
//同為private成員 //插入節點 templatevoid DoubleList ::insertPrivate(DoubleListNode *previous, DoubleListNode *x) { x->prev = previous; x->next = previous->next; previous->next->prev = x; previous->next = x; }
//刪除節點 templatevoid DoubleList ::removePrivate(DoubleListNode *x) { if (x == first) throw std::range_error("permission denied to delete first pointer"); x->prev->next = x->next; x->next->prev = x->prev; delete x; }
提供給客戶的插入:
//插入到表尾 templatevoid DoubleList ::push_back(const Type &data) { DoubleListNode *newNode = new DoubleListNode (data); //找到first的前一個節點 DoubleListNode *previous = first->prev; //插入 insertPrivate(previous, newNode); } //插入到表頭 template void DoubleList ::push_front(const Type &data) { DoubleListNode *newNode = new DoubleListNode (data); //插入到first之後 insertPrivate(first, newNode); } //插入到任意位置(依position指定) template void DoubleList ::insert(int position, const Type &data) { if (position == 1) return push_front(data); int count = 1; //previous 代表著要插入位置之前的一個位置 DoubleListNode *previous = first->next; //如果position過大, 則previous查找到first就會停止 //此時應該將該元素插入到鏈表結尾 while (count < position-1 && previous != first) { ++ count; previous = previous->next; } //如果查找到了鏈表結尾或此時鏈表為空, 因此插入到表尾 if (previous == first) return push_back(data); //如果找到了合適的插入位置 DoubleListNode *newNode = new DoubleListNode (data); insertPrivate(previous, newNode); }
提供給客戶的刪除:
//刪除表尾元素 templatevoid DoubleList ::pop_back() { removePrivate(first->prev); } //刪除表頭元素 template void DoubleList ::pop_front() { removePrivate(first->next); } //刪除元素值為removeData的所有元素 template void DoubleList ::remove(const Type &removeData) { if (isEmpty()) throw std::range_error("link list is empty"); for( DoubleListNode *searchNode = first->next; searchNode != first; searchNode = searchNode->next) { if (searchNode->data == removeData) removePrivate(searchNode); } }
查看是否存在於鏈表中:
templatebool DoubleList ::search(const Type &searchData) const { DoubleListNode *searchNode = first->next; while (searchNode != first) { if (searchNode->data == searchData) return true; searchNode = searchNode->next; } return false; }
輸出鏈表所有元素(測試用):
templateostream &operator<<(ostream &os, const DoubleList &list) { for (DoubleListNode *currentNode = (list.first)->next; currentNode != list.first; currentNode = currentNode->next) os << currentNode->data << ' '; return os; }
//除了添加了operator--, 幾乎沒做任何改變 templateclass ListIterator { public: ListIterator(const DoubleList &_list): list(_list), currentNode((_list.first)->next) {} //重載 *operator const Type &operator*() const throw (std::out_of_range); Type &operator*() throw (std::out_of_range); //重載 ->operator const DoubleListNode *operator->() const throw (std::out_of_range); DoubleListNode *operator->() throw (std::out_of_range); //重載 ++operator ListIterator &operator++() throw (std::out_of_range); //注意:此處返回的是值,而不是reference ListIterator operator++(int) throw (std::out_of_range); //重載 --operator, // 其實這個版本的--operator是不完美的, // 因為他沒有做任何的判錯控制 ListIterator &operator--(); //注意:此處返回的是值,而不是reference ListIterator operator--(int); bool isEmpty() const { return (currentNode == list.first); } private: const DoubleList &list; DoubleListNode *currentNode; };
templateconst Type &ListIterator ::operator*() const throw (std::out_of_range) { if (isEmpty()) throw std::out_of_range("iterator is out of range"); // 返回當前指針指向的內容 return currentNode->data; } template Type &ListIterator ::operator*() throw (std::out_of_range) { return const_cast ( static_cast &>(*this).operator*() ); }
templateconst DoubleListNode *ListIterator ::operator->() const throw (std::out_of_range) { if (isEmpty()) throw std::out_of_range("iterator is out of range"); //直接返回指針 return currentNode; } template DoubleListNode *ListIterator ::operator->() throw (std::out_of_range) { return const_cast *> ( static_cast >(*this).operator->() ); }
templateListIterator &ListIterator ::operator++() throw (std::out_of_range) { if (isEmpty()) throw std::out_of_range("iterator is out of range"); //指針前移 currentNode = currentNode->next; return *this; } template ListIterator ListIterator ::operator++(int) throw (std::out_of_range) { ListIterator tmp(*this); ++ (*this); //調用前向++版本 return tmp; }
templateListIterator &ListIterator ::operator--() { //指針前移 currentNode = currentNode->prev; return *this; } template ListIterator ListIterator ::operator--(int) { ListIterator tmp(*this); -- (*this); return tmp; }
測試代碼:
int main() { cout << "-------- 1 --------" << endl; DoubleListmyList; for (int i = 0; i < 3; ++i) myList.push_back(i+1); for (int i = 0; i < 5; ++i) myList.push_front(10+i); for (int i = 0; i < 3; ++i) myList.push_back(i+1); ListIterator iter(myList), iter2(myList); while (!iter.isEmpty()) { cout << *iter << ' '; ++ iter; ++ iter2; } cout << endl; -- iter2; while (!iter2.isEmpty()) { cout << *iter2 << ' '; iter2 --; } cout << endl; cout << "-------- 2 --------" << endl; cout << myList << endl; cout << "Test insert..." << endl; myList.insert(1, 14); myList.insert(2, 13); myList.insert(2, 13); myList.insert(88, 88); cout << myList << endl; myList.pop_back(); myList.pop_front(); cout << myList << endl; for (int i = 0; i < 5; ++i) { if (myList.search(i)) cout << i << ": Have found!" << endl; else cout << i << ": Not in the list!" << endl; } cout << "Test remove..." << endl; cout << myList << endl; int value; while (cin >> value) { try { myList.remove(value); } catch (const std::exception &e) { cerr << e.what() << endl; } cout << myList << endl; if (myList.isEmpty()) { cout << "empty" << endl; } else { cout << "not empty" << endl; } } return 0; }