"Return to our example with the traffic light. Assume that we want to print the currect state of a specific traffic light. How to do that?\n",
...
...
@@ -333,7 +355,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "5847cc0d",
"id": "76c8886d",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -343,7 +365,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "6a1163c9",
"id": "731e7c94",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -352,7 +374,7 @@
},
{
"cell_type": "markdown",
"id": "e5b29324",
"id": "08b68b2b",
"metadata": {},
"source": [
"Another (neater) way is to associate the state with a corresponding string"
...
...
@@ -361,7 +383,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "e020ca91",
"id": "8fe484bf",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -387,7 +409,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "03890f8b",
"id": "74251bd8",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -397,7 +419,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "bfd20e03",
"id": "5b919ca3",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -406,7 +428,7 @@
},
{
"cell_type": "markdown",
"id": "2919cfda",
"id": "b1718cdd",
"metadata": {},
"source": [
"Another example, demonstrating additional features of ```std::map``` (converted from Gottschling, *Forschung mit modernem C++*)"
...
...
@@ -415,7 +437,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "e46017ba",
"id": "52f631d4",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -463,7 +485,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "c6102380",
"id": "aaba61ba",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -473,7 +495,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "2d71c79e",
"id": "3f9362c9",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -482,7 +504,7 @@
},
{
"cell_type": "markdown",
"id": "26214da5",
"id": "a7e8490c",
"metadata": {},
"source": [
"**Note:** \n",
...
...
@@ -491,7 +513,7 @@
},
{
"cell_type": "markdown",
"id": "afd6c8a0",
"id": "2032e7f2",
"metadata": {},
"source": [
"#### Algorithm\n",
...
...
@@ -503,7 +525,7 @@
},
{
"cell_type": "markdown",
"id": "fe55e848",
"id": "4c239bfa",
"metadata": {},
"source": [
"**Example 1:** Remove double entries from a sequence"
...
...
@@ -512,7 +534,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "a307aade",
"id": "aed454ce",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -549,7 +571,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "f2e2c4d5",
"id": "57c92377",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -559,7 +581,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "b90a9b8a",
"id": "b190c1c6",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -568,7 +590,7 @@
},
{
"cell_type": "markdown",
"id": "f52ee84c",
"id": "e9140c15",
"metadata": {},
"source": [
"**Note:**\n",
...
...
@@ -583,7 +605,7 @@
},
{
"cell_type": "markdown",
"id": "e435d1ec",
"id": "7856aa32",
"metadata": {},
"source": [
"***\n",
...
...
@@ -595,7 +617,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "ecfa4c0a",
"id": "bed09ecd",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -639,7 +661,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "c9c3cb86",
"id": "16a6d2e8",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -649,7 +671,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "499d6af6",
"id": "015eb80f",
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -659,7 +681,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "dc2715fd",
"id": "1efec163",
"metadata": {},
"outputs": [],
"source": []
...
...
%% Cell type:markdown id:bac1d62f tags:
# STL - Part 2 : More Containers & Algorithms
%% Cell type:markdown id:efdc5616 tags:
#### Sets
%% Cell type:code id:c2848a05 tags:
``` C++14
#include <iostream>
#include <set>
std::set< int > s = {1, 7, 4, 8, 2}; // create a set container and fill it
s.insert(5); // insert another element
s.insert(4);
// check how often an element is inside the set
for ( int i = 0; i < 8; ++i ) {
std::cout << i << " appears " << s.count( i ) << " times\n";
}
```
%% Cell type:markdown id:44573775 tags:
**Remarks:**
- Although we inserted **4** twice, it is only stored once in the set data structure. Just like a mathematical set a ```std::set``` can contain a specific object only once.
- Hence, ```count()``` will always return either 0 or 1.
- This shows that ```std::set``` is no sequence container.
- Instead it stores its elements in a **sorted** fashion. This guarantees logarithmic complexity for element access.
%% Cell type:markdown id:a415d236 tags:
Of course we can store various kinds of objects in a set ...
%% Cell type:code id:2213e98e tags:
``` C++14
struct myPair {
myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};
int fir_;
int sec_;
};
std::set< myPair > pairs;
```
%% Cell type:markdown id:725387bc tags:
... but there is a caveat. Check what happens, when we try to insert an object of type ```myPair``` into the set:
%% Cell type:code id:a84d9620 tags:
%% Cell type:code id:51fd5597 tags:
``` C++14
pairs.insert( myPair(1,2) );
```
%% Cell type:markdown id:2ee8f731 tags:
**What went wrong?**
As the set stores its elements in a **sorted** fashion it needs some way to **order** them.
By default that standard ```<``` relation is used.
That does not work for our ```pair``` data type.
We need to define our own comparison operator for the class.
There are plenty ways of doing that. Below we will use a free function for it.
%% Cell type:code id:e8c29594 tags:
``` C++14
%%file demo.cpp
#include <iostream>
#include <set>
struct myPair {
myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};
int fir_;
int sec_;
};
// our comparison function will return true, if the sum of the squares
// of the values in left is smaller than that in right
bool cmp( const myPair& left, const myPair& right ) {
int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;
int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;
The STL offers a variant **```std::unordered_set```** that stores its elements in an unsorted fashion. However, that would not solve our problem. Instead of a **comparison** we then would need to implement a **hashing function**.
%% Cell type:markdown id:59ab93ca tags:
***
The way we added the new element in the example, i.e. via
```pairs.insert( myPair(1,2) );```
again induced a copy operation. As with ```vector``` and ```list``` we could use ```emplace()``` instead.
For demonstration purposes we make the constructor of ```myPair``` verbose.
%% Cell type:code id:bdda6c33 tags:
``` C++14
%%file demo.cpp
#include <iostream>
#include <set>
struct myPair {
myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {
> In computer science, an **associative array**, **map**, **symbol table**, or **dictionary** is an abstract data type composed of a collection of **(key, value) pairs**, such that each possible key appears at most once in the collection.
>
> Operations associated with this data type allow to:
>
>- add a pair to the collection;
>- remove a pair from the collection;
>- modify an existing pair;
>- lookup a value associated with a particular key.
The STL also offers associative containers. An example is ```std::map```.
%% Cell type:markdown id:a942d3bd tags:
%% Cell type:markdown id:fb3ef7bb tags:
Return to our example with the traffic light. Assume that we want to print the currect state of a specific traffic light. How to do that?
Well, using an enumeration for the state we can use the classical switch-case-construct:
// can use at(), if we know the pair to exists, returns value for key
// will throw an "out_of_range" exception, if we were wrong
std::cout << "Value of Euler constant is " << constants.at( "e" ) << "\n\n";
// range-based loop
for ( auto& c: constants ) {
std::cout << "Value of " << c.first << " is " << c.second << '\n';
}
}
```
%% Cell type:code id:c6102380 tags:
%% Cell type:code id:aaba61ba tags:
``` C++14
!g++ constants.cpp
```
%% Cell type:code id:2d71c79e tags:
%% Cell type:code id:3f9362c9 tags:
``` C++14
!./a.out
```
%% Cell type:markdown id:26214da5 tags:
%% Cell type:markdown id:a7e8490c tags:
**Note:**
As with ```set``` there is also a variant of ```map``` that uses hashing instead of ordered storage and is called ```unordered_map```.
%% Cell type:markdown id:afd6c8a0 tags:
%% Cell type:markdown id:2032e7f2 tags:
#### Algorithm
The STL supports also various algorithms that work on the entries in a container. The advantage again is that these save us implementation and will (potentially) work for various kinds of containers.
We will briefly look at two examples.
%% Cell type:markdown id:fe55e848 tags:
%% Cell type:markdown id:4c239bfa tags:
**Example 1:** Remove double entries from a sequence
Container::iterator last = unique( begin(box), end(box) );
print( box, "<- happened in-place" );
box.resize( distance( box.begin(), last ) );
print( box, " <- truncated to new length" );
}
```
%% Cell type:code id:f2e2c4d5 tags:
%% Cell type:code id:57c92377 tags:
``` C++14
!g++ uniq.cpp
```
%% Cell type:code id:b90a9b8a tags:
%% Cell type:code id:b190c1c6 tags:
``` C++14
!./a.out
```
%% Cell type:markdown id:f52ee84c tags:
%% Cell type:markdown id:e9140c15 tags:
**Note:**
Replacing ```vector``` by ```list``` via
using Container = std::vector<int>;
will not work in this example. ```std::sort()``` is implemented to work with a **random access iterator**, which list does not provide. Instead it has its own ```list::sort()```
and ```list::unique()``` member functions.
%% Cell type:markdown id:e435d1ec tags:
%% Cell type:markdown id:7856aa32 tags:
***
**Example 2:** Performing reductions on an array
The STL also provides some algorithms for performing numeric operations. For these we need to include ```<numeric>```.
%% Cell type:code id:ecfa4c0a tags:
%% Cell type:code id:bed09ecd tags:
``` C++14
%%file accumulate.cpp
#include <numeric>
#include <vector>
#include <iostream>
int alternate( int a, int b ) {
static bool odd = false; // static preserves value of local variable
if( odd ) {
odd = false;
return a-b;
}
else {
odd = true;
return a+b;
}
}
int main() {
std::vector<int> v{1, 2, 3, 4, 5};
int gs = std::accumulate( v.begin(), v.end(), 0 );
std::cout << "sum is " << gs << std::endl;
int check = std::accumulate( v.begin(), v.end(), -15 );