diff --git a/notebooks/07_STL_part2.ipynb b/notebooks/07_STL_part2.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..8ab29aaf27b52f9aecd121e0c83462150f96ee7d
--- /dev/null
+++ b/notebooks/07_STL_part2.ipynb
@@ -0,0 +1,365 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "bac1d62f",
+   "metadata": {},
+   "source": [
+    "# STL - Part 2 : More Containers & Algorithms"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "efdc5616",
+   "metadata": {},
+   "source": [
+    "#### Sets"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "c2848a05",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0 appears 0 times\n",
+      "1 appears 1 times\n",
+      "2 appears 1 times\n",
+      "3 appears 0 times\n",
+      "4 appears 1 times\n",
+      "5 appears 1 times\n",
+      "6 appears 0 times\n",
+      "7 appears 1 times\n"
+     ]
+    }
+   ],
+   "source": [
+    "#include <iostream>\n",
+    "#include <set>\n",
+    "\n",
+    "std::set< int > s = {1, 7, 4, 8, 2};   // create a set container and fill it\n",
+    "\n",
+    "s.insert(5);   // insert another element\n",
+    "s.insert(4);\n",
+    "\n",
+    "// check how often an element is inside the set\n",
+    "for ( int i = 0; i < 8; ++i ) {\n",
+    "    std::cout << i << \" appears \" << s.count( i ) << \" times\\n\";\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "44573775",
+   "metadata": {},
+   "source": [
+    "**Remarks:**\n",
+    "- Although we inserted **4** twice it is only stored once in the set datastructure. Just like a mathematical set a ```std::set``` can contain a specific object only once.\n",
+    "- Hence, ```count()``` will always return either 0 or 1.\n",
+    "- This shows that ```std::set``` is no sequence container.\n",
+    "- Instead it stores its elements in a **sorted** fashion. This guarantees logarithmic complexity for element access."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a415d236",
+   "metadata": {},
+   "source": [
+    "Of course we can store various kinds of objects in a set ..."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "2213e98e",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "struct myPair {\n",
+    "  myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};\n",
+    "  int fir_;\n",
+    "  int sec_;\n",
+    "};\n",
+    "\n",
+    "std::set< myPair > pairs; "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "725387bc",
+   "metadata": {},
+   "source": [
+    "... but there is a caveat. Check what happens, when we try to insert an object of type ```myPair``` into the set:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e62cf3d6",
+   "metadata": {},
+   "source": [
+    "pairs.insert( myPair(1,2) );"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2ee8f731",
+   "metadata": {},
+   "source": [
+    "What went wrong?\n",
+    "\n",
+    "As the set stores its elements in an **sorted** fashion it needs some way to **order** them.\n",
+    "By default a ```<``` relation is used.\n",
+    "\n",
+    "That does not work for our ```pair``` datatype.\n",
+    "\n",
+    "Need to define a comparison operator for the class.\n",
+    "\n",
+    "There are plenty ways of doing that. Below we will use a free function for it."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "id": "e8c29594",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Overwriting demo.cpp\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%file demo.cpp\n",
+    "\n",
+    "#include <iostream>\n",
+    "#include <set>\n",
+    "\n",
+    "struct myPair {\n",
+    "  myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};\n",
+    "  int fir_;\n",
+    "  int sec_;\n",
+    "};\n",
+    "\n",
+    "// our comparison function: will return true, if the square of the values\n",
+    "// in left is smaller than that in right\n",
+    "bool cmp( const myPair& left, const myPair& right ) {\n",
+    "  int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n",
+    "  int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n",
+    "  return val1 < val2;\n",
+    "}\n",
+    "\n",
+    "int main() {\n",
+    "    \n",
+    "    // create two objects\n",
+    "    myPair p1( 1, 2 );\n",
+    "    myPair p2( 3, 4 );\n",
+    "\n",
+    "    // compare them\n",
+    "    std::cout << \"p1 < p2 is \" << cmp( p1, p2 ) << std::endl;\n",
+    "    std::cout << \"p2 < p1 is \" << cmp( p2, p1 ) << std::endl;\n",
+    "\n",
+    "    // a free function in C/C++ is represented by the address of its machine code in memory;\n",
+    "    // we can pass that info as a second template argument;\n",
+    "    // decltype returns the type of an expression\n",
+    "    std::set< myPair, decltype( cmp )* > pairs ( cmp );\n",
+    "\n",
+    "    // now insertion will work\n",
+    "    pairs.insert( p1 );\n",
+    "    pairs.insert( p2 );\n",
+    "\n",
+    "    std::cout << \"done with set demo\" << std::endl;\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "id": "0a0207dd",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "!g++ demo.cpp"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "id": "68e1df4b",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "p1 < p2 is 1\n",
+      "p2 < p1 is 0\n",
+      "done with set demo\n"
+     ]
+    }
+   ],
+   "source": [
+    "!./a.out"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f8b3109b",
+   "metadata": {},
+   "source": [
+    "**Note:**  \n",
+    "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",
+   "metadata": {},
+   "source": [
+    "***\n",
+    "The way we added the new element in the example, i.e. via\n",
+    "\n",
+    "```pairs.insert( myPair(1,2) );```\n",
+    "\n",
+    "again induced a copy operation. As with ```vector``` and ```list``` we could use ```emplace()``` instead."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "id": "bdda6c33",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Overwriting demo.cpp\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%file demo.cpp\n",
+    "\n",
+    "#include <iostream>\n",
+    "#include <set>\n",
+    "\n",
+    "struct myPair {\n",
+    "  myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {\n",
+    "      std::cout << \"(\" << fir_ << \",\" << sec_ << \") constructed\" << std::endl;\n",
+    "  };\n",
+    " \n",
+    "  int fir_;\n",
+    "  int sec_;\n",
+    "};\n",
+    "\n",
+    "// our comparison function: will return true, if the square of the values\n",
+    "// in left is smaller than that in right\n",
+    "bool cmp( const myPair& left, const myPair& right ) {\n",
+    "  int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n",
+    "  int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n",
+    "  return val1 < val2;\n",
+    "}\n",
+    "\n",
+    "int main() {\n",
+    "    \n",
+    "    std::set< myPair, decltype( cmp )* > pairs( cmp );\n",
+    "\n",
+    "    pairs.emplace( 1, 2 );\n",
+    "    pairs.emplace( 3, 4 );\n",
+    "    pairs.emplace( 1, 2 );\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "id": "8099d1a4",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "!g++ demo.cpp"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "id": "5d491b27",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(1,2) constructed\n",
+      "(3,4) constructed\n",
+      "(1,2) constructed\n"
+     ]
+    }
+   ],
+   "source": [
+    "!./a.out"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "8e256275",
+   "metadata": {},
+   "source": [
+    "#### Associative Containers\n",
+    "\n",
+    "> Quoting Wikipedia:\n",
+    ">\n",
+    "> 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. Not to be confused with Associative Processors\n",
+    ">\n",
+    "> Operations associated with this data type allow to:\n",
+    ">\n",
+    ">-    add a pair to the collection;\n",
+    ">-    remove a pair from the collection;\n",
+    ">-    modify an existing pair;\n",
+    ">-    lookup a value associated with a particular key.\n",
+    "\n",
+    "    \n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f6269079",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "59839aea",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "C++14",
+   "language": "C++14",
+   "name": "xcpp14"
+  },
+  "language_info": {
+   "codemirror_mode": "text/x-c++src",
+   "file_extension": ".cpp",
+   "mimetype": "text/x-c++src",
+   "name": "c++",
+   "version": "14"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}