Free tutorials & notes in Hindi & English · Clean code examples · Mobile friendly learning
📘 Lesson  ·  Lesson 75

Vectors and Maps

Written and reviewed by · Senior IT Faculty · 15+ years’ experience

Vector or Map: Decide from Meaning

std::vector<T> represents an ordered sequence of values in contiguous storage. std::map<Key, T> represents key-value associations ordered by unique keys. They are not interchangeable performance switches; they model different questions:

  • “What is the third score?” suggests a sequence and possibly a vector.
  • “What score belongs to Sara?” suggests a key-value association and possibly a map.
  • “Preserve insertion order and look up names” may need a vector plus an index, or another deliberately designed structure.
QuestionVectorMap
Primary identityPosition/indexKey
Iteration orderSequence orderComparator/key order
StorageContiguous elementsNode-based ordered association
Duplicate identityValues may repeatKeys are unique; values may repeat
Faculty rule: choose the structure whose invariants express the problem correctly; then evaluate complexity and measured performance.

Vector Deep Dive: Size, Capacity and Safe Access

#include <vector>

std::vector<int> scores;
scores.reserve(100);       // capacity at least 100; size is still 0
scores.push_back(78);      // size becomes 1
scores.emplace_back(91);   // constructs an element at the end

int first = scores[0];     // no bounds check
int checked = scores.at(1); // throws std::out_of_range if invalid

Vector supports constant-time indexing and amortized constant-time insertion at the end. “Amortized” means occasional growth may allocate a larger block and move/copy existing elements, while a sequence of push-backs has constant average cost per insertion under the guarantee.

reserve(n) requests capacity for at least n elements but creates none. resize(n) changes the size and creates/removes elements. This is invalid:

std::vector<int> values;
values.reserve(10);
// values[0] = 7;  // error: size is still zero

Use push_back, emplace_back or resize before indexing. Read the dedicated C++ vector tutorial for construction and member functions.

Map Deep Dive: Ordered Keys and Lookup

#include <map>
#include <string>

std::map<std::string, int> marks{
    {"Sara", 91}, {"Aman", 78}
};

marks.insert_or_assign("Aman", 83);

if (auto it = marks.find("Sara"); it != marks.end()) {
    std::cout << it->second;
}

if (marks.contains("Kabir")) { /* C++20 */ }

A map maintains elements in the order defined by its comparator (ascending std::less by default). Search, insertion and erasure are logarithmic. The standard specifies behavior and complexity, not a mandatory tree implementation.

Be precise with access:

  • m[key] returns the value and inserts a value-initialized entry when the key is absent.
  • m.at(key) does not insert and throws std::out_of_range when missing.
  • m.find(key) returns an iterator; it works before C++20.
  • m.contains(key) returns a boolean since C++20.
  • try_emplace avoids constructing the mapped value when the key already exists.

For sets and associative fundamentals, see C++ set and map.

Combined Vector-and-Map Program with Output

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

int main() {
    std::vector<int> scores{78, 91, 84, 91};
    std::sort(scores.begin(), scores.end());

    std::cout << "Sorted scores:";
    for (int score : scores) std::cout << ' ' << score;

    std::map<std::string, int> by_name{
        {"Sara", 91}, {"Aman", 78}, {"Kabir", 84}
    };
    by_name.at("Aman") += 5;

    std::cout << "\nBy name:";
    for (const auto& [name, score] : by_name) {
        std::cout << ' ' << name << ':' << score;
    }
}
Sorted scores: 78 84 91 91 By name: Aman:83 Kabir:84 Sara:91

The vector preserves duplicate scores and is sorted by value. The map produces key order, not insertion order: Aman, Kabir, Sara. The structured binding binds each pair as name and score; const auto& avoids copying.

Complexity Comparison and Alternatives

Operationvectormap
Index by positionO(1)Not supported
AppendAmortized O(1)Not a sequence operation
Insert/erase middleO(n) movementO(log n) by key
Find in unsorted dataO(n)O(log n)
Find in sorted dataO(log n) comparisons with lower_boundO(log n)
Ordered traversalSequence/sorted only if maintainedAlways comparator order
Memory localityStrong contiguous localityNode overhead and pointer traversal

A sorted vector can be excellent for read-heavy small or medium data: compact storage, binary search and fast traversal. Its insertion remains O(n). A map is valuable when ordered keyed updates are frequent and stable element handles matter.

If ordering is irrelevant, consider unordered_map: expected average constant lookup, but worst-case linear behavior, hash requirements, rehashing and no stable sorted iteration. Big-O alone does not decide real speed; benchmark representative data.

Iteration, Mutation and Invalidation

Vector rules that matter

  • If an operation changes capacity, all iterators, pointers and references to elements are invalidated.
  • Without reallocation, inserting invalidates handles at or after the insertion position; erase invalidates the erased position and everything after it.
  • reserve can reduce repeated reallocations, but calling a later larger reserve can itself reallocate.

Map rules that matter

  • Insertion/emplacement does not invalidate existing iterators and references.
  • Erasure invalidates only iterators/references to erased elements.
  • Do not dereference end(); after erase, use the returned next iterator where appropriate.
for (auto it = by_name.begin(); it != by_name.end(); ) {
    if (it->second < 40) it = by_name.erase(it);
    else ++it;
}

In range-for loops, use const auto& for read-only access and auto& when modifying mapped values. A map key is const through its iterator; changing it in place would violate ordering. Erase and insert under the new key instead.

Real Design Patterns

1. Sorted report plus keyed lookup

If an application needs both insertion order and name lookup, a map alone cannot preserve insertion order. One design stores records in a vector and keeps a separate map from key to stable identifier/index. Define how erasure and vector relocation affect the index.

2. Frequency table

std::map<std::string, int> frequency;
for (const std::string& word : words) {
    ++frequency[word]; // insertion is intentional here
}

Here operator[] is ideal because a missing count should begin at zero.

3. Read-mostly flat data

std::vector<std::pair<std::string, int>> records;
std::sort(records.begin(), records.end());
auto it = std::lower_bound(records.begin(), records.end(),
                           std::pair{std::string{"Sara"}, 0});

This can be compact and cache-friendly, but duplicates, comparator semantics and update cost must be designed deliberately. Prefer clear standard containers until profiling demonstrates a need for a more complex dual structure.

Common Mistakes and Review Checklist

MistakeCorrection
reserve then indexUse push/resize; capacity is not size
map[key] for read-only testUse find/contains/at
Assuming map insertion orderExpect comparator/key order
Storing vector iterator across growthReacquire after possible reallocation
Changing a map key in placeErase and reinsert
Calling every logarithmic structure fasterMeasure constants, cache and workload
Parallel vectors that drift apartUse a record/struct per entity
  1. Is identity positional or keyed?
  2. Must iteration be sorted, insertion-ordered or arbitrary?
  3. Are duplicate keys allowed?
  4. What are the dominant operations?
  5. Must pointers/references stay valid?
  6. Can a lookup modify the structure?
  7. Are empty and missing-key cases tested?
  8. Are warnings and sanitizers used in development?

Authoritative References

Complexity, access and invalidation claims were checked against the current working draft. These guarantees matter more than a particular vendor's internal implementation.

Vector या Map: Meaning से चुनें

vector<T> contiguous ordered sequence है; map<Key,T> unique ordered keys के साथ associations रखता है। “तीसरा score” positional/vector question है; “Sara का score” keyed/map question है।

PropertyVectorMap
IdentityIndexKey
OrderSequenceComparator/key
StorageContiguousNode-based association
DuplicatesValues repeat हो सकते हैंKeys unique
Rule: पहले problem का correct invariant, फिर complexity और measurement।

Vector Deep Dive

std::vector<int> scores;
scores.reserve(100); // capacity, size अभी 0
scores.push_back(78);
scores.emplace_back(91);
int checked=scores.at(1);

Index O(1), end insertion amortized O(1)। Growth पर कभी larger block allocate और elements move/copy होते हैं। reserve capacity बदलता है पर elements नहीं बनाता; resize size बदलता और elements बनाता/हटाता है। इसलिए reserve के बाद values[0] तब तक invalid है जब तक size zero है। vector tutorial पढ़ें।

Map Deep Dive

std::map<std::string,int> marks{{"Sara",91},{"Aman",78}};
marks.insert_or_assign("Aman",83);
if(auto it=marks.find("Sara");it!=marks.end())
 std::cout<<it->second;
if(marks.contains("Kabir")){ /* C++20 */ }

Map comparator order maintain करता और search/insert/erase O(log n) देता है। Standard किसी specific tree implementation को mandate नहीं करता।

  • m[key] missing key पर default mapped value insert करता है।
  • at insert नहीं करता; missing पर exception।
  • find iterator देता है; contains C++20 boolean देता है।
  • try_emplace existing key में unnecessary mapped construction बचा सकता है।

set/map lesson भी देखें।

Combined Practical Lab और Output

std::vector<int> scores{78,91,84,91};
std::sort(scores.begin(),scores.end());
std::map<std::string,int> by_name{
 {"Sara",91},{"Aman",78},{"Kabir",84}};
by_name.at("Aman")+=5;
for(const auto& [name,score]:by_name)
 std::cout<<name<<':'<<score<<' ';
Sorted scores: 78 84 91 91 By name: Aman:83 Kabir:84 Sara:91

Vector duplicates रखता और values के अनुसार sort हुआ। Map insertion order नहीं, key order में Aman, Kabir, Sara देता है। const auto& copy बचाता है।

Complexity Comparison

Operationvectormap
IndexO(1)नहीं
AppendAmortized O(1)Sequence operation नहीं
Middle insertO(n)O(log n) by key
Unsorted findO(n)O(log n)
Sorted findlower_bound O(log n) comparisonsO(log n)
LocalityStrongNode overhead

Read-heavy data में sorted vector compact और fast हो सकता है, पर updates O(n)। Order न चाहिए तो unordered_map average O(1), worst O(n), rehash और unordered iteration देता है। Representative benchmark करें।

Iteration और Invalidation

  • Vector capacity change हो तो सभी element iterators/pointers/references invalid।
  • No reallocation में insert position और बाद के handles invalid; erase erased और बाद के handles invalid।
  • Map insert existing handles valid रखता है; erase केवल erased element के handles invalid करता है।
for(auto it=by_name.begin();it!=by_name.end();){
 if(it->second<40) it=by_name.erase(it);
 else ++it;
}

Read-only range loop में const auto&, mapped value modify करने में auto&। Iterator द्वारा map key const है; key बदलनी हो तो erase/reinsert करें।

Real Design Patterns

Frequency table

std::map<std::string,int> frequency;
for(const std::string& word:words) ++frequency[word];

यहां [] intentional है: missing count zero से शुरू होना चाहिए।

Insertion order + lookup

Map अकेला insertion order preserve नहीं करता। Records vector और key-to-index map रख सकते हैं, लेकिन erase/reallocation से index consistency design करनी होगी।

Read-mostly data

Sorted vector<pair<Key,Value>> + lower_bound compact हो सकता है; duplicates, comparator और update cost carefully define करें। Profiling से जरूरत सिद्ध होने तक simple standard design रखें।

Mistakes और Checklist

MistakeCorrection
reserve के बाद indexpush/resize करें
Read test में map[]find/contains/at
Map insertion orderKey order expect करें
Growth के बाद iteratorReacquire करें
Map key in-place changeErase/reinsert
Big-O ही speedWorkload measure करें
  1. Positional या keyed identity?
  2. Required iteration order?
  3. Duplicates?
  4. Dominant operations?
  5. Handle stability?
  6. Lookup modification allowed?
  7. Missing/empty tests?
  8. Warnings/sanitizers?

Authoritative संदर्भ

Complexity, access और invalidation claims current working draft से verified हैं; vendor implementation के बजाय guarantees पर code design करें।

अक्सर पूछे जाने वाले प्रश्न (FAQ)

C++ में vector और map का मुख्य अंतर क्या है?
vector contiguous index-based sequence है; map unique ordered keys के साथ key-value pairs रखता है। Positional data के लिए vector और meaningful key lookup के लिए map चुनें।
क्या map lookup हमेशा vector से तेज है?
नहीं। Map lookup O(log n) है और vector scan O(n), लेकिन छोटा contiguous vector practical रूप से तेज हो सकता है। Sorted vector में lower_bound भी logarithmic comparisons देता है।
vector reserve और resize में क्या अंतर है?
reserve capacity बदलता है, size/elements नहीं। resize elements की संख्या बदलकर construction या removal करता है। केवल reserved, unconstructed index को access करना invalid है।
map operator[] lookup में risky क्यों है?
Missing key पर operator[] value-initialized mapped value insert करता है। Modification न चाहिए तो find, C++20 contains या at प्रयोग करें।
क्या map insert पुराने iterators invalidate करता है?
Normal map insertion existing iterators/references invalidate नहीं करता। Erase केवल erased element के handles invalidate करता है; vector reallocation सभी handles invalidate कर सकती है।
← Back to C++ Tutorial
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।