From d186706c29a5bca8de6c8f989a80249a98c97b6e Mon Sep 17 00:00:00 2001 From: Marcus Mohr <marcus.mohr@lmu.de> Date: Mon, 29 Nov 2021 19:20:59 +0100 Subject: [PATCH] Starts 2nd notebook on the STL --- notebooks/07_STL_part2.ipynb | 365 +++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 notebooks/07_STL_part2.ipynb diff --git a/notebooks/07_STL_part2.ipynb b/notebooks/07_STL_part2.ipynb new file mode 100644 index 0000000..8ab29aa --- /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 +} -- GitLab