雙向鏈表的操作特點:
(1) “查詢” 和單鏈表相同;
(2)“插入” 和“刪除”時需要同時修改兩個方向上的指針。
但是對於雙向循環鏈表則在表尾插入非常的迅速, 只需O(1)的時間,因爲有指向前面的指針, 因此雙向循環鏈表會很容易的找到位於表尾的元素,因此雙向循環鏈表比較適用於頻繁在表尾插入的情況.
空鏈表:
雙向循環鏈表節點構造:
- class DoubleListNode
- {
- private:
- Type data;
- DoubleListNode *prev; //前向指針域
- DoubleListNode *next; //後項指針域
- };
因爲需要將其用於DoubleList類,因此需要將其改造如下:
- template <typename Type>
- class DoubleListNode
- {
- //友元聲明
- friend class DoubleList<Type>;
- friend class ListIterator<Type>;
- template <typename T>
- friend ostream &operator<<(ostream &os, const DoubleList<T> &list);
- private:
- DoubleListNode(const Type &dataValue)
- :data(dataValue),prev(NULL),next(NULL) {}
- Type data;
- DoubleListNode *prev; //前向指針域
- DoubleListNode *next; //後項指針域
- };
雙向循環鏈表構造:
- template <typename Type>
- class DoubleList
- {
- friend class ListIterator<Type>;
- template <typename T>
- friend ostream &operator<<(ostream &os, const DoubleList<T> &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<Type> *previous,
- DoubleListNode<Type> *x);
- void removePrivate(DoubleListNode<Type> *x);
- private:
- DoubleListNode<Type> *first;
- };
鏈表的構造與析構:
- //構造鏈表
- template <typename Type>
- DoubleList<Type>::DoubleList()
- {
- first = new DoubleListNode<Type>(0);
- first->next = first;
- first->prev = first;
- }
- //析構鏈表
- template <typename Type>
- DoubleList<Type>::~DoubleList()
- {
- DoubleListNode<Type> *deleteNode = NULL;
- //保存鏈表尾元素
- DoubleListNode<Type> *tmp = first;
- //first首先指向第一個真實的元素
- first = first->next;
- //一路到達鏈表結尾
- while (first != tmp)
- {
- deleteNode = first;
- first = first -> next;
- delete deleteNode;
- }
- // 釋放掉鏈表的空節點(表頭)
- delete tmp;
- }
鏈表元素插入與刪除的兩大主力:
- //同爲private成員
- //插入節點
- template <typename Type>
- void DoubleList<Type>::insertPrivate(DoubleListNode<Type> *previous,
- DoubleListNode<Type> *x)
- {
- x->prev = previous;
- x->next = previous->next;
- previous->next->prev = x;
- previous->next = x;
- }
- //刪除節點
- template <typename Type>
- void DoubleList<Type>::removePrivate(DoubleListNode<Type> *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;
- }
提供給客戶的插入:
- //插入到表尾
- template <typename Type>
- void DoubleList<Type>::push_back(const Type &data)
- {
- DoubleListNode<Type> *newNode = new DoubleListNode<Type>(data);
- //找到first的前一個節點
- DoubleListNode<Type> *previous = first->prev;
- //插入
- insertPrivate(previous, newNode);
- }
- //插入到表頭
- template <typename Type>
- void DoubleList<Type>::push_front(const Type &data)
- {
- DoubleListNode<Type> *newNode = new DoubleListNode<Type>(data);
- //插入到first之後
- insertPrivate(first, newNode);
- }
- //插入到任意位置(依position指定)
- template <typename Type>
- void DoubleList<Type>::insert(int position, const Type &data)
- {
- if (position == 1)
- return push_front(data);
- int count = 1;
- //previous 代表着要插入位置之前的一個位置
- DoubleListNode<Type> *previous = first->next;
- //如果position過大, 則previous查找到first就會停止
- //此時應該將該元素插入到鏈表結尾
- while (count < position-1 && previous != first)
- {
- ++ count;
- previous = previous->next;
- }
- //如果查找到了鏈表結尾或此時鏈表爲空, 因此插入到表尾
- if (previous == first)
- return push_back(data);
- //如果找到了合適的插入位置
- DoubleListNode<Type> *newNode = new DoubleListNode<Type>(data);
- insertPrivate(previous, newNode);
- }
提供給客戶的刪除:
- //刪除表尾元素
- template <typename Type>
- void DoubleList<Type>::pop_back()
- {
- removePrivate(first->prev);
- }
- //刪除表頭元素
- template <typename Type>
- void DoubleList<Type>::pop_front()
- {
- removePrivate(first->next);
- }
- //刪除元素值爲removeData的所有元素
- template <typename Type>
- void DoubleList<Type>::remove(const Type &removeData)
- {
- if (isEmpty())
- throw std::range_error("link list is empty");
- for( DoubleListNode<Type> *searchNode = first->next;
- searchNode != first;
- searchNode = searchNode->next)
- {
- if (searchNode->data == removeData)
- removePrivate(searchNode);
- }
- }
查看是否存在於鏈表中:
- template <typename Type>
- bool DoubleList<Type>::search(const Type &searchData) const
- {
- DoubleListNode<Type> *searchNode = first->next;
- while (searchNode != first)
- {
- if (searchNode->data == searchData)
- return true;
- searchNode = searchNode->next;
- }
- return false;
- }
輸出鏈表所有元素(測試用):
- template <typename Type>
- ostream &operator<<(ostream &os, const DoubleList<Type> &list)
- {
- for (DoubleListNode<Type> *currentNode = (list.first)->next;
- currentNode != list.first;
- currentNode = currentNode->next)
- os << currentNode->data << ' ';
- return os;
- }
雙向循環鏈表迭代器的設計與實現:
- //除了添加了operator--, 幾乎沒做任何改變
- template <typename Type>
- class ListIterator
- {
- public:
- ListIterator(const DoubleList<Type> &_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<Type> *operator->() const throw (std::out_of_range);
- DoubleListNode<Type> *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<Type> &list;
- DoubleListNode<Type> *currentNode;
- };
- template <typename Type>
- const Type &ListIterator<Type>::operator*() const
- throw (std::out_of_range)
- {
- if (isEmpty())
- throw std::out_of_range("iterator is out of range");
- // 返回當前指針指向的內容
- return currentNode->data;
- }
- template <typename Type>
- Type &ListIterator<Type>::operator*()
- throw (std::out_of_range)
- {
- return
- const_cast<Type &>(
- static_cast<const ListIterator<Type> &>(*this).operator*()
- );
- }
- template <typename Type>
- const DoubleListNode<Type> *ListIterator<Type>::operator->() const
- throw (std::out_of_range)
- {
- if (isEmpty())
- throw std::out_of_range("iterator is out of range");
- //直接返回指針
- return currentNode;
- }
- template <typename Type>
- DoubleListNode<Type> *ListIterator<Type>::operator->()
- throw (std::out_of_range)
- {
- return
- const_cast<DoubleListNode<Type> *> (
- static_cast<const ListIterator<Type> >(*this).operator->()
- );
- }
- template <typename Type>
- ListIterator<Type> &ListIterator<Type>::operator++()
- throw (std::out_of_range)
- {
- if (isEmpty())
- throw std::out_of_range("iterator is out of range");
- //指針前移
- currentNode = currentNode->next;
- return *this;
- }
- template <typename Type>
- ListIterator<Type> ListIterator<Type>::operator++(int)
- throw (std::out_of_range)
- {
- ListIterator tmp(*this);
- ++ (*this); //調用前向++版本
- return tmp;
- }
- template <typename Type>
- ListIterator<Type> &ListIterator<Type>::operator--()
- {
- //指針前移
- currentNode = currentNode->prev;
- return *this;
- }
- template <typename Type>
- ListIterator<Type> ListIterator<Type>::operator--(int)
- {
- ListIterator<Type> tmp(*this);
- -- (*this);
- return tmp;
- }
測試代碼:
- int main()
- {
- cout << "-------- 1 --------" << endl;
- DoubleList<int> myList;
- 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<int> 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;
- }