Selected C++ Example #10 // Example #10 // This example illustrates the necessary changes to Example // #4a when adding a LinkedRing as a new derived class of // LinkedList. #include <iostream.h> #include <new.h> typedef int DATUM; // The LinkedRing class requires that we abstract out the // test for the end of a list into a separate, protected // polymorphic ''at_end()''method. Since, in a LinkedRing, // the beginning and end tests of a list are equivalent (i.e., // the pointer you have is equal to the head), the loops in // the linked list methods had to be inverted from while to // do-while. In addition to these changes, we had to add a // protected polymorphic method to handle the different // initialization of a node' s next pointer. LinkedList assigns // it to NULL, while a LinkedRing assigns it to itself (to make // a ring of one node). // Requiring a change to the base class when a new derived // class is added to an existing hierarchy occurs more often // than not. This certainly has caused some reusability // problems when inheritance is involved. class LinkedList { protected: struct Node { DATUM data; Node* next; public: Node(const DATUM&); }; virtual Node* ifind(const DATUM&) const; virtual Node* rfind(const DATUM&) const; virtual int at_end(const Node*) const; virtual void set_next(Node*); void cleanup(); Node* get_head() const; private: Node* head; int length; public: LinkedList(); ~LinkedList(); int insert(const DATUM&); int remove(const DATUM&); void traverse() const; virtual char* type(); void test(); }; // The at_end method for the LinkedList simply checks the // current_ptr against NULL. int LinkedList::at_end(const Node* current_ptr) const { return(current_ptr == NULL); } // The set_next method is used to distinguish the LinkedList // versus LinkedRing behavior of creating nodes. The // LinkedList wants a NULL next pointer, while the LinkedRing // wants the next point to reference the object that owns // it. void LinkedList::set_next(Node* new_node) { new_node->next = NULL; } LinkedList::Node* LinkedList::get_head() const { return(head); } LinkedList::Node* LinkedList::ifind(const DATUM&) const { Node* temp = head; if (temp == NULL) { return(NULL); } while (!at_end(temp->next)) { temp = temp->next; } return(temp); } // The remove find method returns three possible values. A // return of -1 implies that the object to be removed is at // the head of the list, NULL implies the item is not in // the list, any other value implies the pointer returned // is a pointer to the preceding node in the list. LinkedList::Node* LinkedList::rfind(const DATUM& bad_item) const { Node* found = head, *pre_found = (Node*) -1; if (head != NULL) { do { if (found->data == bad_item) { return(pre_found); } pre_found = found; found = found->next; } while (!at_end(found)); } return(NULL); } LinkedList::Node::Node(const DATUM& new_data) { data = new_data; next = NULL; } LinkedList::LinkedList() { head = NULL; length = 0; } LinkedList::~LinkedList() { if (head != NULL) cleanup(); } void LinkedList::cleanup() { Node *temp, *current_ptr = head; do { temp = current_ptr; current_ptr = current_ptr->next; delete temp; } while (!at_end(current_ptr)); head = NULL; } int LinkedList::insert(const DATUM& new_item) { Node* temp = ifind(new_item); Node* new_node = new Node(new_item); if (head == NULL) { //Insertion into an empty list set_next(new_node); head = new_node; } else if (temp == NULL) { // Insertion at the head new_node->next = head; head = new_node; } else { //All others new_node->next = temp->next; temp->next = new_node; } return(++length); } // Remove gets more complicated because LinkedRings are a // pain when you need to remove their head node. This // method does not remove the head node until it is the last // thing in the list. It will copy the second node' s data // into the head node and delete the second node instead. int LinkedList::remove(const DATUM& bad_item) { Node* found = rfind(bad_item); Node* temp; if (found == NULL) { // The item is not in the list. return(0); } // The item is in the list, so decrement the count. Then check // if it is the head, which we want to delete. If it is, then // check if it is the last item in the list. If so, then // simply get rid of it. If not, we need to copy the second // node's data and throw away the second node (to preserve the // last node in the list's next pointer to the head). length--; if (found == (Node*) -1) { if (!at_end(head->next)){ head->data = head->next->data; temp = head->next; head->next = head->next->next; delete temp; } else { delete head; head = NULL; } return(1); } else { temp = found->next; found->next = found->next->next; delete temp; return(1); } } void LinkedList::traverse()const { Node* temp = head; cout << ''(''; if (head != NULL) { do { cout << temp->data << '' ''; temp = temp->next; } while(!at_end(temp)); } cout << '')\n''; } char* LinkedList::type() { return(''LinkedList''); } // Note the major reuse of the LinkedList abstraction in this // class. The SortedLinkedList need only redefine three // protected polymorphic methods from the LinkedList. class SortedLinkedList:public LinkedList { protected: Node* ifind(const DATUM&) const; Node* rfind(const DATUM&) const; public: char* type(); }; LinkedList::Node* SortedLinkedList::ifind(const DATUM& new_item) const { Node *found = get_head(),*pre_found = NULL; while (found != NULL && found->data < new_item) { pre_found = found; found = found->next; } return(pre_found); } LinkedList::Node* SortedLinkedList::rfind(const DATUM& bad_item) const { Node* found = get_head(), *pre_found = (Node*)-1; while (found != NULL && found->data <= bad_item) { if (found->data == bad_item) { return(pre_found); } pre_found = found; found = found->next; } return(NULL); } char* SortedLinkedList::type() { return(''SortedLinkedList''); } class LinkedRing:public LinkedList { protected: int at_end(const Node*) const; void set_next(Node*); public: ~LinkedRing(); char* type(); }; LinkedRing::~LinkedRing() { if (get_head() != NULL) cleanup(); } // The at_end method of a LinkedRing checks if the current // pointer is equal to the head pointer. int LinkedRing::at_end(const Node* current_ptr) const { return(current_ptr == get_head()); } void LinkedRing::set_next(Node* new_node) { new_node->next = new_node; } char* LinkedRing::type() { return(''LinkedRing''); } void main() { LinkedList x; SortedLinkedList y; LinkedRing z; cout << ''Testing the LinkedList.\n''; x.test(); cout << ''\n\nTesting the SortedLinkedList.\n''; y.test(); cout << ''\n\nTesting the LinkedRing.\n''; z.test(); } void LinkedList::test() { char c='a'; DATUM num; int size; while (c != 'q') { cout << ''Your '' << type() << '' looks like: ''; traverse(); cout << ''What's your pleasure i)nsert, d)elete, q)uit? ''; cin >> c; if (c == 'i') { cout << ''Number to insert: ''; cin >> num; size = insert(num); cout << ''Number of elements on the '' << type(); cout << '' is '' << size << -.\n" } else if (c == 'd') { cout << ''Number to delete: ''; cin >> num; size = remove(num); if (size == 0) { cout << ''Couldn't find the number \'''' << num; cout << ''\'' in the '' << type() << ''.\n"; } else { cout << ''Found and deleted the number \'''' << num; cout << ''\'' from the '' << type() << ".\n"; } } } } |