Skip to Content

Standard Template Library

Teilaufgabe 1.

Schreiben Sie einen Functor, der zu dem folgenden (und ähnlichen) Programmfragment kompatibel ist, sodass jedes Element des Vektors durch eine gegebene Zahl geteilt wird (im Beispiel 6). Der Functor sollte außerdem überprüfen, ob eine Division durch Null erfolgt und in diesem Fall einen Exception vom Typ invalid_argument werfen.

std::vector <int > numbers_1 = {12, 24, 36, 48, 60, 72, 84, 96}; try { Divide divideBySix (6); std::for_each(numbers_1. begin(), numbers_1.end(), divideBySix); } catch (std:: invalid_argument& e) { std::cout << e.what() << std::endl; }

Antwort:

class Divide { private: int divisor; public: Divide(int d) : divisor(d) {} int operator()(int x) const { if (divisor == 0) throw std::invalid_argument("Division by zero"); return x / divisor; } };

Teilaufgabe 2.

Schreiben Sie ein Predicate, das zu dem folgenden (und ähnlichen) Programmfragment kompatibel ist, sodass der letzte Wert im Vektor zurückgeliefert wird, der eine Quadratzahl ist.

std::vector <int > numbers_2 = {25, 36, 49, 64, 81, 100, 121, 143}; IsSquareNumber isSquareNumber; std::vector<int>::reverse_iterator it2 = std::find_if(numbers_2.rbegin(), numbers_2.rend(), isSquareNumber);

Hinweis: Sie dürfen für die Berechnung double sqrt(double x) der <cmath>-Bibliothek verwenden.

Antwort:

class IsSquareNumber { public: bool operator()(int x) const { return std::sqrt(x) == static_cast<int>(std::sqrt(x)); } };

Tipps

Container

STL-Container speichern Daten in vordefinierten Strukturen. Die häufig verwendeten Container in den Aufgaben sind:

  • std::vector<T>
    Dynamisch wachsende Sequenz, ideal, wenn du eine Liste von Elementen (z. B. Zahlen, Strings oder eigene Objekte) verwalten willst.
    Beispiel:

    #include <vector> std::vector<int> numbers = {1, 2, 3, 4, 5};
  • std::map<Key, T>
    Assoziatives Container, der Schlüssel-Wert-Paare speichert. Er ist sortiert nach den Schlüsseln.
    Beispiel:

    #include <map> std::map<std::string, int> wordFrequency; wordFrequency["hello"] = 3;
  • std::pair<T1, T2>
    Hilfsklasse, um zwei zusammengehörige Werte zu speichern. Wird häufig in Kombination mit Container verwendet (z. B. bei std::map).
    Beispiel:

    #include <utility> std::pair<std::string, int> entry("hello", 3);

Algorithmen und Iteratoren

STL bietet eine Vielzahl von Algorithmen, die du mit den Container-Iterators verwenden kannst. Einige Beispiele:

  • std::for_each
    Führt eine Funktion (oder einen Funktor bzw. Lambda) für jedes Element in einem Bereich aus.
    Beispiel:

    #include <algorithm> #include <vector> #include <iostream> class Divide { int divisor; public: Divide(int d) : divisor(d) {} void operator()(int &x) const { if(divisor == 0) throw std::invalid_argument("Division by zero"); x = x / divisor; } }; int main() { std::vector<int> numbers = {12, 24, 36, 48}; try { Divide divideBySix(6); std::for_each(numbers.begin(), numbers.end(), divideBySix); } catch(const std::invalid_argument& e) { std::cout << e.what() << std::endl; } return 0; }

    Beachte, dass in diesem Beispiel der Funktor so implementiert werden kann, dass er das Element modifiziert (daher als Parameter oft per Referenz übergeben wird).

  • std::find_if
    Sucht in einem Bereich das erste Element, für das ein Prädikat true zurückgibt.
    Beispiel:

    #include <algorithm> #include <vector> #include <cmath> class IsSquareNumber { public: bool operator()(int x) const { double root = std::sqrt(x); return root == static_cast<int>(root); } }; int main() { std::vector<int> numbers = {25, 36, 49, 64, 81, 100, 121, 143}; auto it = std::find_if(numbers.rbegin(), numbers.rend(), IsSquareNumber()); if (it != numbers.rend()) { std::cout << "Gefunden: " << *it << std::endl; } return 0; }

    Hier wird ein Reverse-Iterator verwendet, um vom Ende des Vektors nach vorne zu suchen.

  • std::sort
    Sortiert Elemente in einem Container. Mit einem Lambda (oder Funktor) kann eine benutzerdefinierte Vergleichsfunktion angegeben werden.
    Beispiel (aus der Wortzählung):

    #include <vector> #include <map> #include <algorithm> #include <iostream> // Annahme: wordFrequency ist ein map<string, int> std::map<std::string, int> wordFrequency = {{"der", 4}, {"Hund", 3}, {"springt", 2}}; std::vector<std::pair<std::string, int>> wordVector(wordFrequency.begin(), wordFrequency.end()); // Absteigend nach Häufigkeit sortieren: std::sort(wordVector.begin(), wordVector.end(), [](const auto &a, const auto &b) { return a.second > b.second; }); for (const auto& entry : wordVector) { std::cout << entry.first << ": " << entry.second << std::endl; }
  • Iteratoren (z. B. begin(), end(), rbegin(), rend())
    Diese ermöglichen es dir, über die Container zu iterieren – auch in umgekehrter Reihenfolge (reverse iterator). Iteratoren können mit std::sort verwendet werden, um die Elemente zu sortieren.


Funktoren (Function Objects)

  • Funktoren:
    Dies sind Klassen, die den Funktionsaufrufsoperator operator() überladen. Sie erlauben es, einen Zustand (zum Beispiel den Divisor) zu speichern.
    Beispiel Divide:
    class Divide { int divisor; public: Divide(int d) : divisor(d) {} int operator()(int x) const { if(divisor == 0) throw std::invalid_argument("Division by zero"); return x / divisor; } };

<cmath>

  • std::sqrt(x): Berechnet die Quadratwurzel von x.
  • std::pow(x, y): Berechnet x hoch y.
  • std::sin(x), std::cos(x), std::tan(x): Berechnen die Sinus, Cosinus und Tangens von x.
  • std::log(x), std::log10(x): Berechnen die natürliche und dekadische Logarithmus von x.
  • std::exp(x): Berechnet die Exponentialfunktion von x.
  • std::fabs(x): Berechnet den Absolutwert von x.
Last updated on