Data Structures and Algorithms

The Standard Template Library

The C++ Standard Template Library, included in C++11, is a high-quality library of implementations of the best algorithms and data structures at your fingertips (with plenty of documentation). The implementations are entirely in .h files, so there is no linking necessary.

Some things contained in the STL:

  • Containers and iterators
  • Memory allocators
  • Utilities and function objects
  • Algorithms

Benefits

  • DIY implementation is difficult. Introsort, red-black trees, hash-tables, mergesort... you don't have to know how they work to use them.
  • Uniformity. A lot of the algorithms and data structures are templated, so their interfaces are relatively similar.
  • Saves a lot of debugging time. Greater than half of development time is spent testing and debugging, so if you don't have to do something yourself then you can save a lot of time.

Drawbacks

  • Sometimes, more specific implementations may be faster. Often, if you know that you're not going to encounter a test case, then you can make trade-offs that can make your code faster in some way.
  • You need to understand the library well to fully utilize it. The library has specific implementations of data structures and algorithms, and you have to know the complexity of operations - how well they perform.

The STL uses a lot of C++ features in its implementation, including:

  • Type bool
  • const-correctness and const-casts
  • Namespaces
  • Templates
  • Inline functions
  • Exception handling
  • Keywords explicit and mutable

And so on. You do not, however, need to know what these features do to use their power.

Learning

It's nearly impossible to memorize the entire STL. It's not even necessary. Instead, it's helpful to know what's out there, and how to look things up when you need them.

Generic Programming

A lot of the STL minimizes use of pointers and dynamic memory allocation, so the debugging time is greatly decreased.

Also, since everything is templated, a lot of the same algorithms can be used with multiple data structures!

Complexity

Most STL implementations have the best possible big-O complexities, given their interface. There are two notable exceptions:

  • nth_element()
  • Linked lists

Examples of Containers

Miscellaneous:

vector<>
deque<>
bit_vector<>  // same as vector<bool>
set<>
multi_set<>
map<>
multi_map<>
list<>
array<>

Linked list containers:

list<>          // doubly linked, .size() in O(1)
slist<>         // singly linked, .size() in O(n)
forward_list<>  // singly linked, .size() does not exist

Copying and Sorting

Do this.

#include <algorithm>

copy(vec.begin(), vec.end(), arr); // copy over
copy(arr, arr + SIZE, vec.begin()); // copy back

sort(arr, arr + SIZE);
sort(v.begin(), v.end());

Don't do this.

auto it = vec.begin();
int i = 0;
while (it != vec.end()) {
    arr[i] = *it;
    i++;
}

Or anything of the variety. Using builtins like sort() and copy() is a lot safer and in a more functional style.

Memory Allocation

Data structure Memory overhead
vector<> Compact
list<> Not very compact
unordered_map<> Memory hog

If memory is a worry, don't use an unordered_map<>.

Utilities and Functional Programming

  • There are some functions that perform common operations, like swap<> and max<>.
  • C++11 introduced lambdas instead of functors, which are basically anonymous functors.
void double_all(std::vector<int> & v) {
    std::for_each(v.begin(), v.end(), [](int in) {in *= 2;});
}

Pretty nifty, right? There is also the function std::transform(), which copies the lambda's return value to each element.

Sorting Custom Classes

Let's say, however, that you want to sort a custom class. Instead of overloading the operator<(), use a functional object as your comparison and then use standard library tools.

struct SortByName {
    bool operator()(const Employee & left,
                    const Employee & right) const {
        return left.getName() < right.getName();                
    }
};

You can then use it like so:

vector<Employee> people(100);
// fill them
SortByName nameSort();
sort(people.begin(), people.end(), nameSort);

Generating Random Permutations

This is a little tidbit which is great for testing your program.

srand(time(nullptr));
vector<int> perm(N);

// fill it up
for (unsigned int i = 0; i < N; i++) {
    perm[i] = i;
}

random_shuffle(perm.begin(), perm.end());

You can also sort arrays by using:

random_shuffle(perm, perm + N);

Filling an Array (iota())

You can use the iota() function instead of using a loop:

iota(vec.begin(), vec.end(), 0);  // fills all elements with 0

Debugging

Crashes can occur in STL code, but started by an error in your code and not the library. In GDB, you can use the where or bt commands to find the code that calls the STL and find what happens from there.

Most of the errors related to STL are use of user's dangling pointers or references going out of scope, but that the container still uses.