Lists
This review discusses the concept of Abstract Data Types (ADTs) and specifically focuses on the List ADT, including its operations and design considerations. It also provides an example of a List ADT implementation for integers in C++.
Lists
E N D
Presentation Transcript
Review: ADTs • A concept, not an implementation • A set of (homogeneous) objects together with a set of operations on those objects • No mention of how the operations are implemented • No rules tell which operations are required • A design decision
Review: ADTs (con’t) • From the outside, the user sees only a collection of operations that together define the behavior of the abstraction. • The user also sees how to use the operations (via the operation interfaces). • On the other side, the programmer implementing the abstraction sees the data variables that are used to maintain the state.
A List ADT • A list is a dynamic, homogeneous tuple (set of ordered items) A1, A2, A3, …, An where Ai is the ithitem in the list. • The position of item Ai is i. Positions range from 1 to n, inclusive. • The size of a list is n. • A list of containing no items is called an empty list.
Typical List Operations • Construct a new empty list • Construct a new list as a copy of an existing list • Destroy the list • Make the list empty • Insert an element into the list • Remove an element from the list • Locate the position of an item in the list • Find the value of the nth item in the list • Assign one list to another • Determine if the list is full • Determine if the list is empty • Print the list
Design Considerations • How many items will the list be able to hold? • Some maximum number • An “infinite” number (how will this be handled?) • Will duplicate items be allowed? If so, how will this affect insert, delete, print, etc.? • Positions should be numbered from 1 – N in keeping with the ADT definition
Example ADT: List of Integers • All lists work the same way, regardless of the type of data stored in the list. We’ll use a list of integers for our discussion. • We will follow this procedure: • Outline assumptions that we will make about a list • Decide on the list operations • Translate the list operations into their C++ interfaces, deciding which will be public, private, and friends • Be careful not to make any assumptions about how the list will actually be represented (e.g., an array, a linked list).
Design Assumptions: • The list will be a list of integers. • Notice that we did not say “int’s”. How the integers are implemented will be decided later (ints, strings, or some other representation). • The list can hold a maximum of 100 items numbered 1 - 100 • The list can be empty. • Duplicate items will not be allowed.
Design (con’t) Operations: • Construct a new empty list • Construct a new list as a copy of an existing list • Destroy the list • Assign one list to another • Determine if the list is full • Determine if the list is empty • Make the list empty • Find the value of the kth item in the list • Locate the position of an item in the list • Insert an element into the list • Remove an element from the list • Print the list
Operation Interfaces • Construct a new empty list // default constructor IntList::IntList(int initialSize = 100); • Construct a new list as a copy of an existing list // copy constructor IntList::IntList(const IntList& rhs);
Operation Interfaces (con’t) • Destroy the list // destructor IntList::~IntList( ); • Make the list empty void IntList::makeEmpty( );
Operation Interfaces (con’t) • Check for an empty list bool IntList::isEmpty ( ) const; • Check for a full list bool IntList::isFull ( ) const;
Operation Interfaces (con’t) • Assign one list to another IntList& IntList::operator= (const IntList&);
Operation Interfaces (con’t) • Insert an item into the list • Design decision: • Boolean function • If the item is already in the list, return false and do nothing • Data, not a “package” (such as a node with it’s next pointer) are send to the funciton bool IntList::insert(int x); • What do you think of this design decision?
Operation Interfaces (con’t) • Remove an item from the list • Design Decision: • Boolean function • If the item is not in the list, return false and do nothing bool IntList::remove(int x); • What do you think of this design decision?
Operation Interfaces (con’t) • Locate the position of an item in the list • Design decision: • Positions will be numbered from 1 - N • If the item is not in the list, return 0 int IntList::findPosition(int x) const; • What do you think of this design decision?
Operation Interfaces (con’t) • Return the item in the kth position • Design Decision: • If the position is out of range, return 0. int IntList::operator[ ] (int k) const; • What do you think of this design decision?
Operation Interfaces (con’t) • Print the list • Design decision: • Overload the << operator rather than create a named function • Make operator<< a friend of the IntList class ostream& operator<< (ostream&, const IntList &); • What do you think of this design decision?
IntList Interface class IntList { friend ostream& operator<<(ostream& out, const IntList &L);public: IntList (int size = 100); IntList (const IntList&); ~IntList ( ); IntList& operator= (const IntList &); void makeEmpty ( ); int operator[ ] (int position) const; int findPosition (int x) const; bool insert (int x); bool remove (int x); bool isFull ( ) const; bool isEmpty ( ) const; private: // private data and methods };
Using IntList IntList L1; // a list with room for 100 integers int x; L1.insert (7); L1.insert (42); x = L1[1]; cout << L1 << endl; L1.remove (22); if (! L1.isEmpty ( ) ) L1. makeEmpty ( ) ;
Using IntList (cont’d) Observations: • Client (application/user) code can only use public methods and friend functions provided by IntList. • We can now choose any data representation for the IntList that we want to with no impact on the client code. • If the representation changes later, there is no impact on the client code (except for possible recompilation).
Using IntList (cont’d) • We deliver the interface (.H) to the customer in source code form. • It doesn’t matter if the application programmer sees the representation. He/she still has no direct access to an IntList. .
IntList Implementation • Choices: • array • linked list • Regardless of the choice, we need to store the following information: • maximum capacity of the list • actual size of the list • the list items
Array Implementation class IntList { friend . . . public: . . . private: // private member functions here int capacity; int size; int *theArray;};
Linked List Implementation I struct Node { // using a struct as a node int data; Node* next; }; class IntList { friend . . . public: . . . private: // private member functions here int capacity; int size; Node *theList;};
Linked List Implementation II class Node { // using an object as a node Node( int d = 0, Node* n = NULL ); int data; Node* next; friend class IntList; }; class IntList { public: // same as before private: // private member functions here int capacity; int size; Node *head;};
Array vs. Linked List • What are my memory requirements? • What are my response time requirements? • What is the asymptotic performance of each method for each implementation? • Will the list be used by other applications for other types of data? • How easy is it to generalize the list implementation (e.g., using templates)?
Generalized Linked List template <class DATATYPE> class List; // forward declaration template <class DATATYPE> class Node { friend class List<DATATYPE>; Node( const DATATYPE& d = DATATYPE( ), DATATYPE * n = NULL); DATATYPE data; Node<DATATYPE>* next; };
Generalized Linked List (con’t) template <class DATATYPE> class List { public: . . . bool insert(const DATATYPE &data); DATATYPE operator[ ] (int k) const; . . . private: // private member functions here int capacity; int size; Node<DATATYPE> *theList;};
Generalized Linked List (con’t) #include “list.H” int main( ) { List<int> integerList; List<SomeClass> someList; . . . return 0; } (See your text for more details on the generalized linked list implementation.)