An Introduction to Data Structures

## Lecture Goals

• To be able to write programs with standard lists and iterators
• To understand the advantages and disadvantages of the list data structure
• To learn about stacks and queues

• Suppose you are maintaining a vector of sorted objects (such as employees)
• Many elements will need to be shifted back if an new object is inserted in the middle.
• Many elements will need to be shifted forward if an object is deleted from the middle.
• Moving a large number of records can involve a substantial amount of computer time - O(n) time.
• Rather than store a sequence of values in one long block of memory (like a vector or an array) a linked list stores each value in its own memory block, together with the locations of the neighboring blocks in the sequence.

• Inserting an element into a list now requires no shifting, merely reassigning new locations to adjacent objects - O(1) time.
• Removing an element from the list doesn't require shifts either - O(1) time.
• The standard C++ library has an implementation of the linked list structure.
• First we will learn how to use the standard list.
• Later we will find out how to implement lists.
• Doubly linked lists (as shown in the illustrations) have links going in both directions.
• Just like the vector, the standard list is a template.
• You can use push_back to add elements to the list.
`list<string> staff;staff.push_back("Cracker, Carl");staff.push_back("Hacker, Harry");staff.push_back("Lam, Larry");staff.push_back("Sandman, Susan");`
• You cannot directly access elements using subscript access (e.g. staff[3]) - the values are not stored in one contiguous block in memory and there is no fast way to access them.
• Instead you must start at the beginning of the list, and visit each element in turn using a list iterator. An iterator marks a position in the list.
`list<string>::iterator pos;pos = staff.begin();`
• To move an iterator forward in the list, use the ++ operator.
`pos++;`
• To move an iterator backward in the list, use the -- operator.
`pos--;`
• You can find the value that is stored in the position with the * operator.
`string value = *pos;`
• The value *pos represent the value that is stored in the list.
`*pos = "Van Dyck, Vicki"; // assign a value pos = staff.begin(); // assign a position   `
• To insert another string before the iterator position, use the insert function.
`staff.insert(pos, "Reindeer, Rudolph");`
• Each list has an end position that does not correspond to any value in the list but that points past the list's end.
`pos = staff.end(); /* points past the end of the list */staff.insert(pos, "Yaglov, Yvonne");   /* insert past the end of list */`
• The end position does not point to any value, so you cannot look up the value at that position.
`string value = *(staff.end()); /* ERROR */`
• Compare to accessing s[10] in a vector with 10 elements.
• The end position is useful for stopping a traversal of the list.
`pos = staff.begin();while (pos != staff.end()){  cout << *pos << "\n";   pos++;}`
• The traversal can be described more concisely with a for loop:
`for (pos = staff.begin(); pos != staff.end(); pos++)   cout << *pos << "\n";`
• Compare this to a traversal of a vector.
`for (i = 0; i < s.size(); i++)   cout << s[i] << "\n";`
• To remove an element from a list, you move an iterator to the position you want to remove, then call the erase function.
`pos = staff.begin();pos++;staff.erase(pos);`

## Stacks and Queues

• Stacks and queues are special data types that allow insertion and remove of items at the ends only, not in the middle.
• A stack lets you insert and remove elements at one end only, traditionally called the top of the stack.
• To visualize a stack, think of a stack of books.
• Since items can only be added or removed from the top of the stack, they are removed in the order that is opposite from the order they were added.
• This is called last in, first out or LIFO order.
• The addition and removal operations are called push and pop.
• The stack is a template in the standard C++ library.
`stack<string> s;s.push("Tom");s.push("Dick");s.push("Harry");while (s.size() > 0){  cout << s.top() << "\n";   s.pop();}`
• A queue is similar to a stack, except that you add items to one end of the queue (the back) and remove them from the other end of the queue (the front).
• To visualize a queue, think of people lining up.
• Queues store items in a first in, first out or FIFO fashion.
• The standard queue template implements a queue in C++.
`queue<string> q;q.push("Tom");q.push("Dick");q.push("Harry");while (q.size() > 0){  cout << q.front() << "\n";   q.pop();}`

## Other Standard Containers

• The standard library contains several other useful containers.
• The set always keeps its elements in order, no matter in which order you insert them.
`set<string> s;s.insert("Tom");s.insert("Dick");s.insert("Harry");set<string>::iterator p;for (p = s.begin(); p!= s.end(); p++)   cout << *p << "\n";`
• The above code displays the strings in sorted order: Dick, Harry, Tom.
• The set data structure keeps the values in a special tree shaped structure; each time an element is inserted, the tree is reorganized.
• The C++ set ignore duplicates; if you insert an element into the set that is already present, the insertion has no effect.
• The count function returns the number of times that an element is contained in a set (should always be 1).
`set<string> s;s.insert("Tom");s.insert("Tom");cout << s.count("Tom") << "\n"; /* displays 1 */`
• If you want to be able to keep track of multiple occurrences of identical values, use a multiset instead.
• The count function works for multiset, with expected results.
`multiset<string> m;m.insert("Tom");m.insert("Tom");cout << m.count("Tom") << "\n"; /* displays 2 */`
• set.cpp
• A map is similar to a vector, but you can use another data type for the indices.
`map<string, double> scores;scores["Tom"] = 90;scores["Dick"] = 86;scores["Harry"] = 100;`
• Multimaps are a kind of associative container that stores elements formed by the combination of a key value and a mapped value, much like map containers, but allowing different elements to have the same key value.
`multimap<string, double> mmap;mmap.insert(pair("Tom", 90));mmap.insert(pair("Dick", 86));mmap.insert(pair("Harry", 100));mmap.insert(pair("Tom", 190));`
• map.cpp

## Standard Algorithms

• Why iterators?
• It is possible to supply generic functions that can carry out a task with the elements in any container that uses iterators.
• Example: The accumulate function can compute the sum of all elements in a vector or a list.
`vector<double> data;/* do something with data */double vsum = 0;accumulate(data.begin, data.end(), vsum);/* now vsum contains the sum of the elements in the vector */list<double> salaries;/* do something with salaries */double lsum = 0;accumulate(salaries.begin(), salaries.end(), lsum);/* now lsum contains the sum of the elements in the list */`
• The standard library also supplies a find algorithm.
• The find algorithm returns the second iterator if the search fails.
`/* search for a certain name on the staff */list<string>::iterator it =   find(staff.begin(), staff.end(), name);`
• The first two parameters can be other iterators for the list (if you don't want to search the entire list).
• The standard library provides a wealth of ready-to-use and fully debugged data structures and algorithms.
• for_each applies a function to each element
• find (as above)
• find_if locates the first element fulfilling a condition
• count (as above)
• equal tests if containers have the same elements in the same order
• replace/replace_if replace all matching elements with a new one
• unique remove adjacent identical values
• min_element, max_element finds the smallest and largest elements
• next_permutation rearranges the elements; call it n! times iterates through all permutations
• sort sorts the elements; stable_sort performs better if the container is already almost sorted
• random_shuffle randomly rearranges the elements
• nth_element find the nth element without sorting the container.
• plus many more...
• Before writing a lot of code from scratch, check whether the standard library already has what you need.