std::multimap


STL container: std::multimap

std::multimap is an associative container in the C++ Standard Template Library (STL) that stores key-value pairs in a sorted order based on the keys, allowing multiple elements with the same key. Like std::map, it is typically implemented as a balanced binary search tree (usually a red-black tree), providing logarithmic time complexity for insertion, deletion, and search operations.

Key Characteristics

Example 1: Basic Usage

#include <iostream>
#include <map>
#include <string>

int main() {
    std::multimap<std::string, int> studentScores;

    // Inserting elements
    studentScores.insert({"Alice", 85});
    studentScores.insert({"Bob", 90});
    studentScores.insert({"Alice", 92});  // Another score for Alice
    studentScores.insert({"Charlie", 88});
    studentScores.insert({"Bob", 95});    // Another score for Bob

    // Iterating through the multimap
    for (const auto& pair : studentScores) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    // Counting entries for a specific key
    std::string name = "Alice";
    std::cout << "Number of scores for " << name << ": " 
              << studentScores.count(name) << std::endl;

    // Finding all scores for a specific student
    auto range = studentScores.equal_range(name);
    std::cout << name << "'s scores: ";
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << it->second << " ";
    }
    std::cout << std::endl;

    // Size of the multimap
    std::cout << "Total number of scores: " << studentScores.size() << std::endl;

    return 0;
}

Explanation:

Example 2: Custom Comparator for Descending Order

#include <iostream>
#include <map>
#include <string>

// Custom comparator for descending order of keys
struct DescendingOrder {
    bool operator()(const std::string& a, const std::string& b) const {
        return a > b;
    }
};

int main() {
    std::multimap<std::string, int, DescendingOrder> fruitInventory;

    fruitInventory.insert({"Apple", 100});
    fruitInventory.insert({"Banana", 150});
    fruitInventory.insert({"Cherry", 75});
    fruitInventory.insert({"Apple", 120});  // Another entry for Apple
    fruitInventory.insert({"Banana", 130}); // Another entry for Banana

    for (const auto& pair : fruitInventory) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

Explanation:

Example 3: Using multimap for Grouping and Analysis

#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <algorithm>

// Structure to represent a sale
struct Sale {
    std::string product;
    double amount;
    std::string date;
};

// Function to print sales summary
void printSalesSummary(const std::multimap<std::string, Sale>& sales) {
    for (const auto& category : sales) {
        std::cout << "Category: " << category.first << std::endl;
        double total = 0.0;
        std::vector<double> amounts;
        for (auto it = sales.lower_bound(category.first); 
             it != sales.upper_bound(category.first); ++it) {
            total += it->second.amount;
            amounts.push_back(it->second.amount);
        }
        std::cout << "  Total Sales: $" << total << std::endl;
        if (!amounts.empty()) {
            std::cout << "  Average Sale: $" << total / amounts.size() << std::endl;
            std::cout << "  Highest Sale: $" << *std::max_element(amounts.begin(), amounts.end()) << std::endl;
        }
        std::cout << std::endl;
    }
}

int main() {
    std::multimap<std::string, Sale> salesData;

    // Inserting sales data
    salesData.insert({"Electronics", {"Laptop", 1200.00, "2023-01-15"}});
    salesData.insert({"Clothing", {"T-Shirt", 25.99, "2023-01-16"}});
    salesData.insert({"Electronics", {"Smartphone", 800.00, "2023-01-17"}});
    salesData.insert({"Clothing", {"Jeans", 59.99, "2023-01-18"}});
    salesData.insert({"Electronics", {"Headphones", 150.00, "2023-01-19"}});
    salesData.insert({"Clothing", {"Dress", 89.99, "2023-01-20"}});

    // Print sales summary
    printSalesSummary(salesData);

    return 0;
}

Explanation:

Example 4: Removing Elements from a multimap

#include <iostream>
#include <map>
#include <string>

void printMultimap(const std::multimap<std::string, int>& mm) {
    for (const auto& pair : mm) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }
    std::cout << "Size: " << mm.size() << std::endl << std::endl;
}

int main() {
    std::multimap<std::string, int> wordCount;

    // Inserting elements
    wordCount.insert({"apple", 1});
    wordCount.insert({"banana", 2});
    wordCount.insert({"apple", 3});
    wordCount.insert({"cherry", 4});
    wordCount.insert({"banana", 5});

    std::cout << "Initial multimap:" << std::endl;
    printMultimap(wordCount);

    // Removing a single element by key
    std::string keyToRemove = "cherry";
    wordCount.erase(keyToRemove);
    std::cout << "After removing '" << keyToRemove << "':" << std::endl;
    printMultimap(wordCount);

    // Removing all elements with a specific key
    keyToRemove = "banana";
    auto removed = wordCount.erase(keyToRemove);
    std::cout << "After removing all '" << keyToRemove << "' (removed " << removed << " elements):" << std::endl;
    printMultimap(wordCount);

    // Removing a single element by iterator
    auto it = wordCount.find("apple");
    if (it != wordCount.end()) {
        wordCount.erase(it);
        std::cout << "After removing one 'apple' entry:" << std::endl;
        printMultimap(wordCount);
    }

    return 0;
}

Explanation:

Additional Considerations

  1. Performance: While multimap provides good performance for most operations, consider using std::unordered_multimap for faster lookup times if sorting is not required.

  2. Memory Usage: Like map, multimap typically uses more memory than simpler data structures due to its tree structure.

  3. No Direct Access: Unlike map, multimap does not provide the [] operator for direct access, as keys are not unique.

  4. Iteration Order: Elements are always traversed in the sorted order defined by the comparison function.

  5. Value Modification: Values can be modified through iterators, but keys cannot be modified directly to maintain the correct ordering.

Summary

std::multimap is a powerful container in C++ for storing multiple key-value pairs with the same key in a sorted order. Key points to remember:

std::multimap is particularly useful in situations where you need to: - Store multiple values associated with a single key in a sorted structure - Implement one-to-many relationships - Group and analyze data by categories - Maintain a sorted collection of elements with potential duplicates

Understanding when to use std::multimap versus other containers like std::map, std::unordered_multimap, or std::vector is crucial for writing efficient and clear C++ code in various application domains. Its ability to handle multiple values per key while maintaining a sorted order makes it a versatile choice for many complex data management scenarios.

Related

Previous Page | Course Schedule | Course Content