590 likes | 657 Views
COS220 Concepts of PLs AUBG, COS dept. Lecture 35a OOP The STL Standard Template Library Reference: MS Developer Studio, Visual C++ , Lafore, Chap 15 STL, pp 726-797. 1. Lecture Title: STL – Sequence Containers sources: R.Lafore, OOP In C++, Chap 15 STL, pp 726-797
E N D
COS220 Concepts of PLs AUBG, COS dept Lecture 35a OOP The STL Standard Template Library Reference: MS Developer Studio, Visual C++ , Lafore, Chap 15 STL, pp 726-797 1
. Lecture Title: STL – Sequence Containers sources: R.Lafore, OOP In C++, Chap 15 STL, pp 726-797 http://www.sgi.com/tech/stl/ http://en.wikipedia.org/wiki/Standard_Template_Library
Lecture contents: • STL – overview • STL – structure and components • Sequence Containers • Algorithms • Associative Containers • Iterators • Practical session
STL • STL contains several kinds of entities. The three most important of them are: • Containers • Sequence containers • Associative containers • Algorithms • Iterators
STL Containers: • A Container is a way that stored data is organized in memory. So, well known typical Data Structures are excellent candidates to implement as containers. • Common containers: • Stack, List, Queue. • Array (most common that built-in to all PL). • STL containers are implemented by template classes <T>, so they may be customized to contain different kinds of data.
STL Algorithms: • Algorithms are Procedures that are applied on containers to process their data in various ways. • E.g. Algorithms to sort, copy, search, merge data. • Algorithms are represented by stand alone template functions (not members of container classes). • Algorithms are so general that can be used not only on STL containers but also on ordinary C++ arrays and on user-specified containers.
STL Iterators: • Generalization of the concept of pointers. They point to element in Container. • Iterator may increment, so it points in turn to each element in Container. • Iterators as key parts of STL, because they connect algorithms with containers. See next slide.
STL - Containers • Container is a way to store data, whether it consists of built-in data types or class objects. • Containers in STL fall in: • Sequence containers – store a set of elements in what you can visualize as a line. Each element is related to the other by its position along the line. Each element except at the ends is preceded by a specific element and followed by another. • Associative containers – are not sequential, instead they use keys to access data. • STL makes 7 basic containers + 3 derived from basic. • Option to create own containers based on basic kinds.
STL – Sequence Containers • Containers in STL fall in: • Sequence containers • vector, list, deque • stack, queue, priority queue • Associative containers • set, multiset, map, multimap • Why so many kinds of containers? The Answer: because of efficiency. An Array is conventional but awkward and slow as a container in many situations.
STL - Sequence Containers • Sequence containers • vector – relocating, expandable array • list – doubly linked list • deque – like vector, but may be accessed at either end
STL – Sequence Containersvector, list, deque • Problems with C++ arrays: • Need To specify size at compile time. STL provides vector as more flexible and efficient container. • Insertion a new element in a sorted array needs to move certain number of elements in order to open the necessary space. STL alternative is list. • Te third sequence container is deque, which can be thought of as a combination of a stack and a queue.
STL – Sequence Containersvector, list, deque =Container=======Characteristics==================Advantage/Disadvantage====== C++ array fixed size quick random access slow to insert/erase in the middle cannot change size at runtime =================================================================== vector relocating quick random access expandable array slow to insert/erase in the middle quick to insert/erase at end =================================================================== list doubly linked list quick to insert/delete at any location quick access to both ends slow random access =================================================================== deque like vector but quick random access can be accessed at slow to insert/erase in the middle either end quick to insert/erase at either the beginning or the end
Instantiating Sequence Containers • First include appropriate header file • Use template format with the kind of objects to be stored as the parameter: vector<int> aVector, theVector; list<airtime> departure_list, arrival_list; • No need to specify size of containers. They themselves take care of all memory allocation.
Instantiating vectors #include <vector> • Default (no argument) constructor vector<int> v1; // create a vector of ints, initial size 0 • One argument constructor: vector<double> v2(4); // empty vector of size 4 • Two argument constructor: double arr[] = { 1.1, 2.2, 3.3, 4.4 }; vector<double> v3(arr, arr+4); // initialize vector to array
Sequence Containers – vectors, vector<t> • Vectors may be thought of as smart arrays. • Vectors manage storage allocation expanding and reducing vector size when insert or erase data. • Vector elements are accessible using [] operator. Such random access is very fast with vectors. • It’s also fast to add (or push) new data item onto the end (the back) of the vector. • When add/erase data item, vector size is automatically modified/updated.
Sequence Containers – vector<t> Member functions push_back(), size(), operator[] • push_back() inserts the value of its argument at the back of the vector (where element with highest index number is). The front of the vector (element with index 0) cannot be used for inserting new elements. • size() returns the number of elements currently in the vector. • operator[] serves to access vector data – read/write. • See file Ch15\Vector.cpp. Example.
Sequence Containers – vector<t> Member functions push_back(), size(), operator[] vector<int> v; // create a vector of ints v.push_back(10); // put values at end of array v.push_back(11); v.push_back(12); v.push_back(13); v[0] = 20; // replace with new values v[3] = 23; for(int j=0; j<v.size(); j++) // display vector contents cout << v[j] << ' '; // 20 11 12 23
Sequence Containers – vector<t> Member functions swap(), empty(), back(), pop_back() • swap() exchanges all the data in one vector with all the data in another keeping the elements in same order. Function swap() exists also as algorithm. • empty() returns true if vector is empty. • back() returns the value of the last element in the vector. • pop_back() removes the last element in the vector. • See file Ch15\Vectcon.cpp. Example.
Sequence Containers – vector<t> Member functions swap(), empty(), back(), pop_back() double arr[] = { 1.1, 2.2, 3.3, 4.4 }; vector<double> v1(arr, arr+4); // initialize vector to array vector<double> v2(4); // empty vector of size 4 v1.swap(v2); // swap contents of v1 and v2 while( !v2.empty() ) // until vector is empty, { cout << v2.back() << ' '; // display the last element v2.pop_back(); // remove the last element } // output: 4.4 3.3 2.2 1.1
Sequence Containers – vector<t> Member functions insert(), erase() • These functions insert/remove an element from an arbitrary location in a container. • Insert() takes two arguments – the place where to insert and the value of the element. Elements from insertion point to the end are moved upward to make room and the vector size is increased by 1. • Erase() removes the element at specified location. Elements above the deletion point are moved downward and the vector size is decreased by 1. • See file Ch15\Vectins.cpp. Example.
Sequence Containers – vector<t> Member functions insert(), erase() int arr[] = { 100, 110, 120, 130 }; //an array of ints vector<int> v(arr, arr+4); // initialize vector to array cout << "\nBefore insertion: "; for(int j=0; j<v.size(); j++) cout << v[j] << ' '; // display all elements v.insert( v.begin()+2, 115); // insert 115 at element 2 cout << "\nAfter insertion: "; for(j=0; j<v.size(); j++) cout << v[j] << ' '; // display all elements v.erase( v.begin()+2 ); // erase element 2 cout << "\nAfter erasure: "; for(j=0; j<v.size(); j++) cout << v[j] << ' '; // display all elements
Sequence Containers – lists, list<t> • An STL list container is a doubly linked list. • Each element contains a pointer to the next element and to the preceding element. • The container stores the address of both the front (first) and the back (last) elements which makes for fast access.
Instantiating lists #include <list> • Default (no argument) constructor list<int> l1; // create a list of ints, initial size 0 • One argument constructor: list<double> l2(4); // empty list of size 4 • Two argument constructor: double arr[] = { 1.1, 2.2, 3.3, 4.4 }; list<double> l3(arr, arr+4); // initialize list to array
Sequence Containers – list<t>, Member functions push_front(), front(), pop_front() • These functions are similar to push_back(), back() pop_back() vector functions. See back slides. • push_front() • front() • pop_front() • Random access not allowed for list elements (slow). • See file Ch15\List.cpp. Example.
Sequence Containers – list<t>, Member functions push_front(), front(), pop_front() list<int> ilist; ilist.push_back(30); // push items on back ilist.push_back(40); ilist.push_front(20); // push items on front ilist.push_front(10); int size = ilist.size(); // number of items for(int j=0; j<size; j++) { cout << ilist.front() << ' '; // read item from front ilist.pop_front(); // pop item off front }
Sequence Containers - list<t>, Member functions reverse(), merge(), unique() • reverse() is used to reverse a list. • merge() serves to merge its list argument into the list container whose method is invoked keeping everything sorted. Both lists should be sorted. • unique() finds adjacent elements with the same value, and removes all but the first. • See file Ch15\Listplus.cpp. Example.
Sequence Containers - list<t>, Member functions reverse(), merge(), unique() list<int> list1, list2; int arr1[] = { 40, 30, 20, 10 }; int arr2[] = { 15, 20, 25, 30, 35 }; for(j=0; j<4; j++) list1.push_back( arr1[j] ); // list1: 40, 30, 20, 10 for(j=0; j<5; j++) list2.push_back( arr2[j] ); // list2: 15, 20, 25, 30, 35 list1.reverse(); // reverse list1: 10 20 30 40 list1.merge(list2); // merge list2 into list1 list1.unique(); // remove duplicate 20 and 30 int size = list1.size(); while( !list1.empty() ) { cout << list1.front() << ' '; // read item from front list1.pop_front(); // pop item off front }
Sequence Containers – deques, deque<t> • A deque is like a vector and like a linked list. • Like a vector, deque supports a random access using the [] operator. • Like a list, a deque can be accessed at the front as well as at the back. • A deque is a sort of double-ended vector with member functions.
Sequence Containers – deque<t>, Member functions • Deque is like a vector in some ways and like a list in other ways.
Instantiating deques #include <deque> • Default (no argument) constructor deque<int> dq1; // create a deque of ints, initial size 0 • One argument constructor: deque<double> dq2(4); // empty deque of size 4 • Two argument constructor: double arr[] = { 1.1, 2.2, 3.3, 4.4 }; deque<double> dq3(arr, arr+4); // initialize deque to array
Sequence Containers – deque<t>, Member functions deque<int> deq; deq.push_back(30); // push items on back deq.push_back(40); deq.push_back(50); deq.push_front(20); // push items on front deq.push_front(10); deq[2] = 33; // change middle item for(int j=0; j<deq.size(); j++) cout << deq[j] << ' '; // display items
STL - Containers • Member functions common to all Containers • size() • empty() • max_size() • begin() • end() • rbegin() • rend()
STL – Sequence Containers, Container Adaptors • It is possible to create special-purpose containers from the normal containers using a construct called container adaptors. The specialized containers implemented with container adaptors in the STL are: • stack, #include <stack> • queue, #include <queue> • priority queue. #include <queue> • Stacks, queues and priority queues can create from different sequence containers, although the deque is often used by default.
STL – Sequence Containers, Container Adapters • A stack restricts access to pushing and popping data items on and off the top of the stack (LIFO). • In a queue, data items are pushed at one end and popped off the other end (FIFO). • In a priority queue, data items are pushed in the front in the random order, but when user pops the data off the other end, he/she always pops the largest item stored: the priority queue automatically sorts the data.
STL – Sequence Containers, the stack • A stack restricts access to pushing and popping data items on and off the top of the stack (LIFO).
STL – Sequence Containers, the queue • The queue container type. Another name for the queue, FIFO, describes the container by the way it normally processes data: First In, First Out. The standard interface to the FIFO queue simply consists of a push() function, which adds new elements, and a pop() function, which always removes the oldest element.
STL – Sequence Containers, the queue • The queue container data structure is relatively easy to implement. However, there are many times when a more sophisticated form of queue is needed. One illustration of a modified queue is the priority queue.
STL–Sequence Containers, the priority queue • Figure from previous slide shows a representation of a priority queue. This type of queue assigns a priority to every element that it stores. New elements are added to the queue using the push() function, just as with a FIFO queue. This queue also has a pop() function, which differs from the FIFO pop() in one key area. When you call pop() for the priority queue, you don't get the oldest element in the queue. Instead, you get the element with the highest priority.
STL–Sequence Containers, the priority queue The priority queue obviously fits in well with certain types of tasks. Two possible applications are: • The scheduler in an operating system might use a priority queue to track processes running in the operating system. • Use of a priority queue to build a Huffman encoding tree.
STL – Sequence Containers, Container Adaptors Container Implementation Characteristic ================================================ Stack as vector, insert (push) and remove list, deque (pop) at one end only. ================================================ Queue as list or insert(push) at one end, deque remove(pop) at other ================================================ Priority as vector or insert(push) in random queue deque order at one end, remove (pop) in sorted order from other end =================================================
STL – Sequence Containers, Container Adaptors Such classes are instantiated using template within template. Example: stack holding int data, instantiated from deque class: stack<int, deque<int> > aStack; Detail: a space is must btw the two closing angle brackets. Otherwise stack<int, deque<int>> aStack; The compiler will interpret >> as an operator
Declaration and Initialization of stack A stack can use either a vector or list or deque (by default) as the underlying container. A declaration for a stack must specify the element type /first class argument/, and can also specify the container that will hold the values /second class argument/. For a stack the default container is a deque, but a vector or a list can also be used. When deciding which in cases where efficiency of either speed or memory is important, you should try all three underlying containers and compare the results. Sample declarations stack: stack<int> s1; // stack using deque implicitly, default stack<double, deque<double> > s2; stack<Part*, list<Part*> > s3; stack<Customer, vector<Customer> > s4; The last example creates a stack from user-defined type named Customer.
Member functions /operations/ of stack FunctionImplemented operation empty() Returns true if the collection is empty. size() Returns number of elements in collection. top() Returns (but does not remove) the topmost element in the stack. push(newElement) Pushes a new element on to the stack. pop() Removes (but does not return) the topmost element from the stack. Note that removing the element at the top of the stack does not return a value. If the value of the element is important, you must retrieve the element before you remove the element.
Demo program STLpage732StackSB.cpp pragma warning(disable:4786) #include <vector> #include <list> #include <deque> #include <stack> #include <iostream> using namespace std;
Demo program STLpage732StackSB.cpp void main() { cout << "\n=============================================\n\n"; stack<int> s1; // stack using deque implicitly by default s1.push(111);s1.push(222);s1.push(333);s1.push(444); while (!s1.empty()) { cout << "s1.top() returned " << s1.top() << endl; cout << "s1.pop()" << endl; s1.pop();} cout << "\n=============================================\n\n"; stack<double, vector<double> > s2; //stack using vector s2.push(111.1);s2.push(222.2);s2.push(333.3);s2.push(444.4); while (!s2.empty()) { cout << "s2.top() returned " << s2.top() << endl; cout << "s2.pop()" << endl; s2.pop(); } cout << "\n=============================================\n\n"; stack<float, list<float> > s3; //stack using list s3.push(11.1f);s3.push(22.2f);s3.push(33.3f);s3.push(44.4f); while (!s3.empty()) { cout << "s3.top() returned " << s3.top() << endl; cout << "s3.pop()" << endl; s3.pop();} }