Recitation Week 14 Object Oriented Programming COP 3330
Recitation Week 14 Object Oriented Programming COP 3330 / CGS 5409
Today’s Recitation � Vectors � Linked � Stacks Lists
Abstract Data Types � C++ has some built-in methods of storing compound data in useful ways, like arrays and structs. � Collectively known as Abstract Data Types, as they describe the nature of what is stored, along with the expected operations for accessing the data, without specifying the details of implementation
Abstract Data Types � C++ classes allow a nice mechanism for implementing such data types � Provides an interface (the public section) for the necessary operations � The actual implementation details are internal and hidden.
Vectors � Data structure that stores items of the same type, and is based on storage in an array � By encapsulating an array into a class (a vector class), we can ◦ Use dynamic allocation to allow the internal array to be flexible in size ◦ Handle boundary issues of the array (error checking for out-of-bounds indices).
Vectors � Advantages: Random access - i. e. quick locating of data if the index is known. � Disadvantages: Inserts and Deletes are typically slow, since they may require shifting many elements to consecutive array slots
Linked Lists � Collections of data items linked together with pointers, lined up "in a row". � Typically a list of data of the same type, like an array, but storage is arranged differently. � Made up of a collection of "nodes", which are created from a self-referential class (or struct).
Linked Lists � Self-referential class: a class whose member data contains at least one pointer that points to an object of the same class type. � Each node contains a piece of data, and a pointer to the next node. � Nodes can be anywhere in memory (not restricted to consecutive slots, like in an array). � Nodes generally allocated dynamically, so a linked list can grow to any size, theoretically (within the boundaries of the program's memory).
Linked Lists � An alternative to array-based storage. � Advantages: Inserts and Deletes are typically fast. Require only creation of a new node, and changing of a few pointers. � Disadvantage: No random access. Possible to build indexing into a linked list class, but locating an element requires walking through the list. � Notice that the advantages of the array (vector) are generally the disadvantages of the linked list, and vice versa
Stacks � First In Last Out (FILO) � Insertions and removals can occur from "top" position only � Analogy - a stack of cafeteria trays. New trays are always placed on top. Trays also picked up from the top.
Stacks �A stack class will have two primary operations: � push stack � pop -- adds an item onto the top of the -- removes the top item from the stack � Typical application areas include compilers, operating systems, handling of program memory (nested function calls)
Queues � First In First Out (FIFO) � Insertions at the "end" of the queue, and removals from the "front" of the queue. � Analogy - waiting in line for a ride at an amusement park. Get in line at the end. First come, first serve.
Queues �A queue class will have two primary operations: � enqueue -- adds an item into the queue (i. e. at the back of the line) � dequeue -- removes an item from the queue (i. e. from the front of the line). � Typical application areas include print job scheduling, operating systems (process scheduling).
Implementing Abstract Types � Some abstract types, like Stacks and Queues, can be implemented with a vector or with a linked list. �A stack can use a linked list as its underlying storage mechanism, for instance, but would limit the access to the list to just the "push" and "pop" concepts (insert and remove from one end).
Trees �A non-linear collection of data items, also linked together with pointers (like a linked list). � Made up of self-referential nodes. In this case, each node may contain 2 or more pointers to other nodes.
Trees � Typical example: a binary tree � Each node contains a data element, and two pointers, each of which points to another node. � Very useful for fast searching and sorting of data, assuming the data is to be kept in some kind of order. � Binary search - finds a path through the tree, starting at the "root", and each chosen path (left or right node) eliminates half of the stored values.
Code Example: Linked Lists � Creates a template doubly linked list of List() type, composed of Listnode() type nodes. � Listnode. h definition. � List. h -- Template List. Node class -- Template List class definition.
Listnode. h #ifndef LISTNODE_H #define LISTNODE_H template< typename T > class List; template< typename T > class List. Node { friend class List< T >; // make List a friend public: List. Node( const T & ); // constructor T get. Data() const; // return data in node private: T data; // data List. Node< T > *next. Ptr; // next node in list };
Listnode. h -- continued // constructor template< typename T > List. Node< T >: : List. Node( const T &info ): data( info ), next. Ptr( 0 ) { } // end List. Node constructor // return copy of data in node template< typename T > T List. Node< T >: : get. Data() const { return data; } // end function get. Data #endif
List. h #ifndef LIST_H #define LIST_H #include <iostream> #include "Listnode. h" // List. Node class definition template< typename T > class List { public: List(); // constructor ~List(); // destructor void insert. At. Front( const T & ); void insert. At. Back( const T & ); bool remove. From. Front( T & ); bool remove. From. Back( T & ); bool is. Empty() const; void print() const; private: List. Node< T > *first. Ptr; // pointer to first node List. Node< T > *last. Ptr; // pointer to last node List. Node< T > *get. New. Node( const T & ); };
List. h -- continued // default constructor template< typename T > List< T >: : List() : first. Ptr( 0 ), last. Ptr( 0 ) { } // end List constructor // destructor template< typename T > List< T >: : ~List() { if ( !is. Empty() ) // List is not empty { cout << "Destroying nodes. . . n"; List. Node< T > *current. Ptr = first. Ptr; List. Node< T > *temp. Ptr; while ( current. Ptr != 0 ) // delete remaining nodes { temp. Ptr = current. Ptr; cout << temp. Ptr->data << 'n'; current. Ptr = current. Ptr->next. Ptr; delete temp. Ptr; } // end while } // end if cout << "All nodes destroyednn";
List. h -- continued / insert node at front of list template< typename T > void List< T >: : insert. At. Front( const T &value ) { List. Node< T > *new. Ptr = get. New. Node( value ); // new node if ( is. Empty() ) // List is empty first. Ptr = last. Ptr = new. Ptr; // new list has only one node else // List is not empty { new. Ptr->next. Ptr = first. Ptr; // point new node to previous 1 st node first. Ptr = new. Ptr; // aim first. Ptr at new node } // end else } // end function insert. At. Front
List. h -- continued // insert node at back of list template< typename T > void List< T >: : insert. At. Back( const T &value ) { List. Node< T > *new. Ptr = get. New. Node( value ); // new node if ( is. Empty() ) // List is empty first. Ptr = last. Ptr = new. Ptr; // new list has only one node else // List is not empty { last. Ptr->next. Ptr = new. Ptr; // update previous last node last. Ptr = new. Ptr; // new last node } // end else } // end function insert. At. Back
List. h -- continued // delete node from front of list template< typename T > bool List< T >: : remove. From. Front( T &value ) { if ( is. Empty() ) // List is empty return false; // delete unsuccessful else { List. Node< T > *temp. Ptr = first. Ptr; // hold temp. Ptr to delete if ( first. Ptr == last. Ptr ) first. Ptr = last. Ptr = 0; // no nodes remain after removal else first. Ptr = first. Ptr->next. Ptr; // point to previous 2 nd node value = temp. Ptr->data; // return data being removed delete temp. Ptr; // reclaim previous front node return true; // delete successful } // end else } // end function remove. From. Front
List. h -- continued // delete node from back of list template< typename T > bool List< T >: : remove. From. Back( T &value ) { if ( is. Empty() ) // List is empty return false; // delete unsuccessful else { List. Node< T > *temp. Ptr = last. Ptr; // hold temp. Ptr to delete if ( first. Ptr == last. Ptr ) // List has one element first. Ptr = last. Ptr = 0; // no nodes remain after removal else { List. Node< T > *current. Ptr = first. Ptr; while ( current. Ptr->next. Ptr != last. Ptr ) // locate second-to-last element current. Ptr = current. Ptr->next. Ptr; // move to next node last. Ptr = current. Ptr; // remove last node current. Ptr->next. Ptr = 0; // this is now the last node } // end else value = temp. Ptr->data; // return value from old last node delete temp. Ptr; // reclaim former last node return true; // delete successful } // end else } // end function remove. From. Back
List. h -- continued // is List empty? template< typename T > bool List< T >: : is. Empty() const { return first. Ptr == 0; } // end function is. Empty // return pointer to newly allocated node template< typename T > List. Node< T > *List< T >: : get. New. Node( const T &value ) { return new List. Node< T >( value ); } // end function get. New. Node
List. h -- continued // display contents of List template< typename T > void List< T >: : print() const { if ( is. Empty() ) { // List is empty cout << "The list is emptynn"; return; } // end if List. Node< T > *current. Ptr = first. Ptr; cout << "The list is: "; while ( current. Ptr != 0 ) { // get element dat cout << current. Ptr->data << ' '; current. Ptr = current. Ptr->next. Ptr; } // end while cout << "nn"; } // end function print #endif
Questions?
- Slides: 28