Sobes.tech
Middle

Τι πρέπει να κάνετε για να αποθηκεύσετε τη δομή σας σε unordered_map;

sobes.tech AI

Απάντηση από AI

Για να αποθηκεύσετε μια δομή ως κλειδί σε std::unordered_map, πρέπει να παρέχετε:

  1. Συνάρτηση κατακερματισμού (hash function): Βρίσκει την τιμή κατακερματισμού για το αντικείμενο της δομής.
  2. Τελεστή σύγκρισης ισότητας (operator==): Συγκρίνει δύο αντικείμενα δομής για ισότητα.

Υπάρχουν διάφοροι τρόποι να παρέχετε αυτά τα στοιχεία:

  • Υπερφόρτωση του operator== μέσα στη δομή και εξειδίκευση του std::hash για τη δομή σας. Αυτή είναι η πιο συνηθισμένη και συστηνόμενη προσέγγιση.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    
        bool operator==(const MyStruct& other) const {
            return id == other.id && name == other.name;
        }
    };
    
    // Εξειδίκευση του std::hash για το MyStruct
    namespace std {
        template <>
        struct hash<MyStruct> {
            size_t operator()(const MyStruct& obj) const {
                size_t h1 = hash<int>()(obj.id);
                size_t h2 = hash<std::string>()(obj.name);
                return h1 ^ (h2 << 1);
            }
        };
    }
    
    // Παράδειγμα χρήσης στο main
    int main() {
        std::unordered_map<MyStruct, int> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
        MyStruct key3 = {1, "Alice"}; // ισοδύναμο με το key1
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        if (my_map.count(key3)) {
            // my_map[key3] θα δώσει 10
        }
    
        return 0;
    }
    
  • Να παρέχετε τις συναρτήσεις κατακερματισμού και σύγκρισης ως ξεχωριστές παραμέτρους του προτύπου κατά την δήλωση του unordered_map. Αυτό είναι λιγότερο βολικό αν χρησιμοποιείτε συχνά τη δομή ως κλειδί, καθώς πρέπει να δηλώνετε τους τύπους του συγκριτή και του κατακερματιστή σε κάθε δήλωση του κοντέινερ.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    };
    
    // Ξεχωριστή συνάρτηση κατακερματισμού
    struct MyStructHash {
        size_t operator()(const MyStruct& obj) const {
            size_t h1 = std::hash<int>()(obj.id);
            size_t h2 = std::hash<std::string>()(obj.name);
            return h1 ^ (h2 << 1);
        }
    };
    
    // Ξεχωριστή συνάρτηση σύγκρισης (ή functor)
    struct MyStructEqual {
        bool operator()(const MyStruct& lhs, const MyStruct& rhs) const {
            return lhs.id == rhs.id && lhs.name == rhs.name;
        }
    };
    
    // Παράδειγμα χρήσης στο main
    int main() {
        std::unordered_map<MyStruct, int, MyStructHash, MyStructEqual> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        return 0;
    }
    

Σημαντικά σημεία:

  • Ορθότητα της συνάρτησης κατακερματισμού: Για οποιαδήποτε δύο κλειδιά a και b, αν a == b, τότε hash(a) πρέπει να είναι ίσο με hash(b). Το αντίστροφο δεν απαιτείται (πιθανές συγκρούσεις).
  • Ποιότητα της συνάρτησης κατακερματισμού: Μια καλή συνάρτηση κατακερματισμού διανέμει ομοιόμορφα τις τιμές κατακερματισμού για διαφορετικά κλειδιά, ελαχιστοποιώντας τις συγκρούσεις και βελτιώνοντας την απόδοση (O(1) κατά μέσο όρο).
  • Σταθερότητα: Οι τελεστές σύγκρισης και η συνάρτηση κατακερματισμού πρέπει να είναι const, καθώς δεν πρέπει να τροποποιούν το αντικείμενο του κλειδιού.