Brief notes on what we can do with an STL list.
First what do we have to do to make the STL linked list template class available?
#include <list>
std::
" or alternatively we can write:using namespace std;
Now what can we do with a list? First we can declare and construct it. STL containers (including lists) provide a number of constructors:
list<int> myList;
list<int> anotherList(myList);
list<int> myOtherList(8, 5);
list<Elephant> myListofElephants(12);
int arr[] = {2, 3, 5, 8, 13, 21};
list<int> listOfInts(arr, arr + 6);
We can do a number of other things with our lists through member functions and overloaded operators:
if (listOfInts == myOtherList) // do something or other...
listOfInts.clear()
listOfInts.reverse();
listOfInts.push_front(17); // adds a new element, 17, to the front of
the list
listOfInts.push_back(17); // adds a new element, 17, to the back of the list
To do much of anything else with our lists we will have to be able to get iterators to access the elements in the list. How do we declare an iterator? And what can we initialize it to? First the declaration. The type "iterator" is actually a sub-type of its container class. What does that mean? When we declare a variable to be an iterator we have to say what kind of container it is an iterator for. Much as pointers have to be declared based on what kind of thing they point to. For an iterator to a list of ints, we could say:
list<int>::iterator myIterator;
Now to make that iterator refer to something. The easiest thing to start with
is the beginning of a list. the list class has a method called begin()
that returns an iterator to the start of the list.
myIterator = listOfInts.begin();
Another method that returns an iterator is end()
. That does not
refer to the last element in the list. Instead it refers to a location
beyond then end of the list. What do we use end() for? To check when
we've finished with the list. We'll look at an example in a moment, but first
we need to be able to do two other things with an iterator.
myIterator++
++myIterator
*myIterator
Putting it all together we can construct a loop to print out the contents of a list:
for (list<int>::iterator i = listOfInts.begin(); i != listOfInts.end(); ++i) cout << *i << endl;
The loop shown above
A couple of important points to remember. First, note that we compare list
iterators by checking for ==
or for !=
. Never
check for "less than" or any other such inequality to compare list
iterators.
Second, we use the increment operator to move from one item to the next. We couldn't do this if we were using pointers in a linked list because the memory used for a list isn't contiguous, instead it may be spread all over and so incrementing with a Node pointer is likely to leave you pointing to some totally unrelated area of memory. But iterators are a special type and using the increment operator has been made to work for them.
With iterators, we can do other things with lists. One important advantage
of lists is that is easy and quick to add elements anywhere into a list. There
are a few functions that help us, such as the member function insert()
.
The code below sets an iterator first to the beginning of the list, then increments
it to point to the second element. Finally, it inserts a new element just before
the second element, so that now 28 is the second element of the list.
list<int>::iterator i = listOfInts.begin();
i++;
listOfInts.insert(i, 28);
It's just as important that we can remove elements. If we want to get rid of the first occurence of 13 in the list, we would first find the item and then erase it. Finding something is a generic operation, which we will talk about more below. Erasing is a member function of the container class. Note that we first need to make sure that we actually did find what we were looking for.
list<int>::iterator where = find(listOfInts.begin(), listOfInts.end(), 13);
if (where != listOfInts.end()) listOfInts.erase(where);
On the other hand, if we want to get rid of all occurences of 13, that's easier. There is a method in the list class that does that!
listOfInts.remove(13); // removes all occurences.
Sorting a list is also done with a member function. The line of code below shows how to sort the whole list.
listOfInts.sort();
The items in the list will be sorted based on the less-than operator for the data that the list holds.
Another way of inserting elements into a list is splicing. The splice member function takes elements out of one container and adds them to another. This is a somewhat unusual function because it has to know not only the range of of elements to splice into, but the container that they come from. The function takes four arguments:
Now that we have iterators we can do lots of other things. In addition to writing loops such as the one above or calling member functions that need iterators, we can also make use of the third major portion of the STL, generic algorithms (the first portion being the containers and the second the iterators). To be able to use the algorithms below, we need to include the appropriate header:
#include <algorithm>
What can we do now? Many more things than we can reasonably talk about here. We'll mention a few. For most generic algorithms the first two arguments are iterators indicating the beginning and the end of the range that the function will act on. Note especially that these functions never know what kind of container they are operating on. They only have the iterators to look at, not the containers.
list<int>::iterator i = find(listOfInts.begin(), listOfInts.end(),
17);
listOfInts
.int total = count(listOfInts.begin(), listOfInts.end(), 17);
copy(listOfInts.begin(), listOfInts.end(), anArrayOfInts);
Maintained by John Sterling (jsterling@poly.edu). Last updated January 23, 2011