Data Structure BASICS (12)-Design and Implementation of two-way circular linked list
Features of two-way linked list operation:
(1) "query" is the same as a single-chain table;
(2) When "insert" and "delete", you must modify the pointer in both directions.
However, for a two-way cyclic linked list, inserting at the end of the table is very fast. It only takes O (1) time, because there is a pointer to the front, therefore, the two-way cyclic linked list can easily find the elements at the end of the table. Therefore, the two-way cyclic linked list is suitable for frequent insertion at the end of the table.
Empty linked list:
Bidirectional cyclic linked list node structure:
Class DoubleListNode {private: Type data; DoubleListNode * prev; // The forward pointer field DoubleListNode * next; // The backward pointer field };
Because you need to use it in the DoubleList class, you need to transform it as follows:
Template
Class DoubleListNode {// friend element declaration 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; // forward pointer field DoubleListNode * next; // backward pointer field };
Bidirectional cyclic linked list structure:
Template
Class 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: // insert node x to the void insertPrivate (DoubleListNode
* Previous, DoubleListNode
* X); void removePrivate (DoubleListNode
* X); private: DoubleListNode
* First ;};
Structure and analysis of linked lists:
// Create a linked list template
DoubleList
: DoubleList () {first = new DoubleListNode
(0); first-> next = first; first-> prev = first ;}
// Analyze the linked list template
DoubleList
::~ DoubleList () {DoubleListNode
* DeleteNode = NULL; // Save the end element of the linked list DoubleListNode
* Tmp = first; // first point to the first real element first = first-> next; // all the way to the end of the linked list while (first! = Tmp) {deleteNode = first; first = first-> next; delete deleteNode;} // release the empty node (header) of the linked list to delete tmp ;}
Two main elements of linked list element insertion and deletion:
// The same as a private member // insert a node template
Void DoubleList
: InsertPrivate (DoubleListNode
* Previous, DoubleListNode
* X) {x-> prev = previous; x-> next = previous-> next; previous-> next-> prev = x; previous-> next = x ;}
// Delete the node template
Void 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 ;}
Insert provided to the customer:
// Insert the template to the end of the table
Void DoubleList
: Push_back (const Type & data) {DoubleListNode
* NewNode = new DoubleListNode
(Data); // locate the first node DoubleListNode
* Previous = first-> prev; // insert insertPrivate (previous, newNode);} // insert it to the header template
Void DoubleList
: Push_front (const Type & data) {DoubleListNode
* NewNode = new DoubleListNode
(Data); // insertPrivate (first, newNode) after being inserted to first;} // insert to any position (specified by position) template
Void DoubleList
: Insert (int position, const Type & data) {if (position = 1) return push_front (data); int count = 1; // previous indicates a position before which DoubleListNode is to be inserted
* Previous = first-> next; // if the position is too large, the previous will stop when it finds the first element. // at this time, the element should be inserted to the end of the linked list while (count <position-1 & previous! = First) {++ count; previous = previous-> next;} // if the end of the linked list is found or the linked list is empty at this time, therefore, insert it to the end of the table if (previous = first) return push_back (data); // if a suitable Insertion Location is found, DoubleListNode
* NewNode = new DoubleListNode
(Data); insertPrivate (previous, newNode );}
Deletion provided to the customer:
// Delete the end element template
Void DoubleList
: Pop_back () {removePrivate (first-> prev);} // Delete the Header element template
Void DoubleList
: Pop_front () {removePrivate (first-> next);} // Delete All template elements whose element value is removeData
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 );}}
Check whether it exists in the linked list:
template
bool DoubleList
::search(const Type &searchData) const{ DoubleListNode
*searchNode = first->next; while (searchNode != first) { if (searchNode->data == searchData) return true; searchNode = searchNode->next; } return false;}
Output all elements of the linked list (for testing ):
template
ostream &operator<<(ostream &os, const DoubleList
&list){ for (DoubleListNode
*currentNode = (list.first)->next; currentNode != list.first; currentNode = currentNode->next) os << currentNode->data << ' '; return os;}
Design and Implementation of a two-way cyclic linked list iterator:
// Except operator -- added, almost no template change is made.
Class ListIterator {public: ListIterator (const DoubleList
& _ List): list (_ list), currentNode (_ list. first)-> next) {}// reload * operator const Type & operator * () const throw (std: out_of_range); Type & operator * () throw (std :: out_of_range); // overload-> operator const DoubleListNode
* Operator-> () const throw (std: out_of_range); DoubleListNode
* Operator-> () throw (std: out_of_range); // overload + + operator ListIterator & operator ++ () throw (std: out_of_range); // note: here, the returned value is not reference ListIterator operator ++ (int) throw (std: out_of_range); // reload -- operator, // In fact, this version -- operator is not perfect, // The ListIterator & operator -- (); // Note: The value returned here is not the reference ListIterator operator -- (int); bool isEmpty () const {return (currentNode = list. first);} private: const DoubleList
& List; DoubleListNode
* CurrentNode ;};
Template
Const Type & ListIterator
: Operator * () constthrow (std: out_of_range) {if (isEmpty () throw std: out_of_range ("iterator is out of range "); // return the content pointed to by the current pointer return currentNode-> data;} template
Type & ListIterator
: Operator * () throw (std: out_of_range) {return const_cast
(Static_cast
&> (* This). operator *());}
Template
Const DoubleListNode
* ListIterator
: Operator-> () constthrow (std: out_of_range) {if (isEmpty () throw std: out_of_range ("iterator is out of range "); // directly return the pointer return currentNode;} template
DoubleListNode
* ListIterator
: Operator-> () throw (std: out_of_range) {return const_cast
*> (Static_cast
> (* This). operator-> ());}
Template
ListIterator
& ListIterator
: Operator ++ () throw (std: out_of_range) {if (isEmpty () throw std: out_of_range ("iterator is out of range "); // forward the pointer to currentNode = currentNode-> next; return * this;} template
ListIterator
ListIterator
: Operator ++ (int) throw (std: out_of_range) {ListIterator tmp (* this); ++ (* this ); // call the forward ++ version return tmp ;}
Template
ListIterator
& ListIterator
: Operator -- () {// Pointer Forward currentNode = currentNode-> prev; return * this;} template
ListIterator
ListIterator
: Operator -- (int) {ListIterator
Tmp (* this); -- (* this); return tmp ;}
Test code:
int main(){ cout << "-------- 1 --------" << endl; DoubleList
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
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;}