Menu
CoddyTech

C++ STL Interview Questions

Which container to pick, what each operation costs, and the traps in map, vector and remove.

13 questions
  1. What is the STL and what are its main components?

    The generic part of the standard library: containers (vector, map, unordered_map...), container adaptors (stack, queue, priority_queue), iterators, algorithms (sort, find, accumulate) and function objects such as lambdas. Algorithms work on iterator ranges, not on containers.

    C++
    #include <algorithm>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        vector<int> v = {5, 2, 9, 1};
        sort(v.begin(), v.end());
        auto it = find(v.begin(), v.end(), 9);
        cout << "sorted: ";
        for (int x : v) cout << x << " ";
        cout << "| 9 at index " << (it - v.begin()) << "\n";
    }

    This prints sorted: 1 2 5 9 | 9 at index 3.

  2. What is the difference between vector, list and deque?

    vectordequelist
    Random accessO(1)O(1)no
    Insert at frontO(n)O(1)O(1)
    Insert in middleO(n)O(n)O(1) with an iterator

    All three add at the end in amortized O(1). Default to vector: one contiguous block beats list even for many middle insertions, because walking a list costs a cache miss per node. Use deque for both ends and list for stable iterators.

  3. What is the difference between map and unordered_map in C++?

    std::map keeps sorted keys in a balanced binary search tree (red-black in the major libraries) with O(log n) operations. std::unordered_map is a hash table with no order, O(1) on average and O(n) in the worst case.

    Use unordered_map for plain lookups and map for sorted output or lower_bound queries. The hash table visualization shows buckets and collisions.

    Practice it: Two Sum, Group Anagrams

  4. In what order does a std::map iterate its keys?

    C++
    #include <iostream>
    #include <map>
    #include <string>
    using namespace std;
    
    int main() {
        map<string, int> m;
        m["pear"] = 3;
        m["apple"] = 5;
        m["fig"] = 1;
        m["apple"] += 1;
        for (auto& [k, v] : m) cout << k << "=" << v << " ";
        cout << "\n";
    }

    It prints apple=6 fig=1 pear=3. std::map keeps its keys sorted, so iteration is alphabetical whatever the insertion order, and m["apple"] += 1 adds to the existing value. With std::unordered_map the order would be unspecified.

  5. What happens when you read a missing key with map[key]?

    C++
    #include <iostream>
    #include <map>
    #include <string>
    using namespace std;
    
    int main() {
        map<string, int> m;
        if (m["missing"] == 0) cout << "zero ";
        cout << m.size() << "\n";
    }

    It prints zero 1. operator[] inserts a value-initialized element when the key is missing, so reading m["missing"] adds the key with value 0.

    To look up without inserting, use m.find(key), m.count(key), m.at(key) (throws if missing) or C++20's m.contains(key).

  6. How does std::vector grow? What is the difference between size and capacity?

    size() is how many elements the vector holds; capacity() is how many fit before it must reallocate. When full, it allocates a block a constant factor larger and moves the elements, so push_back is amortized O(1).

    C++
    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<int> v;
        size_t last = 0;
        for (int i = 0; i < 20; ++i) {
            v.push_back(i);
            if (v.capacity() != last) {
                last = v.capacity();
                std::cout << last << " ";
            }
        }
        std::cout << "\n";
    }

    With GCC's libstdc++ this prints 1 2 4 8 16 32; MSVC grows by 1.5 times. Reallocation invalidates every pointer and iterator. See the vector docs.

  7. What is iterator invalidation? How do you erase from a container while iterating?

    When a container change leaves an iterator pointing at freed or moved memory; using it is undefined behavior. A vector reallocation invalidates all iterators; in list, map and set only the erased element's. To erase while iterating, continue from the iterator erase returns.

    C++
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        vector<int> v = {1, 2, 3, 4, 5, 6};
        for (auto it = v.begin(); it != v.end(); ) {
            if (*it % 2 == 0) it = v.erase(it);
            else ++it;
        }
        for (int x : v) cout << x << " ";
        cout << "\n";
    }

    This prints 1 3 5. More in the iterators docs.

  8. Does std::remove change a vector's size?

    C++
    #include <algorithm>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        vector<int> v = {1, 2, 3, 2, 4, 2};
        auto newEnd = remove(v.begin(), v.end(), 2);
        cout << v.size() << " ";
        v.erase(newEnd, v.end());
        cout << v.size() << "\n";
    }

    It prints 6 3. std::remove only sees iterators, so it cannot change the size: it shifts the kept elements (1, 3, 4) to the front and returns the new logical end. erase then cuts the leftover tail.

    Together that is the erase-remove idiom, v.erase(remove(v.begin(), v.end(), 2), v.end());. C++20's std::erase(v, 2) and std::erase_if do both steps.

    Practice it: Remove Duplicates from Sorted Array, Move Zeroes

  9. Is std::priority_queue a min-heap or a max-heap by default?

    C++
    #include <functional>
    #include <iostream>
    #include <queue>
    #include <vector>
    using namespace std;
    
    int main() {
        priority_queue<int> maxq;
        priority_queue<int, vector<int>, greater<int>> minq;
        for (int x : {4, 1, 7, 3}) {
            maxq.push(x);
            minq.push(x);
        }
        cout << maxq.top() << " " << minq.top() << "\n";
    }

    It prints 7 1. std::priority_queue is a max-heap by default. For a min-heap pass std::greater<int> as the third template argument, which means also naming the container, vector<int>, as the second.

    push and pop are O(log n) and top is O(1). The heap visualization shows a min-heap sifting each value up.

    Practice it: Kth Largest Element in an Array, Last Stone Weight, Top K Frequent Elements

  10. Which algorithm does std::sort use, and how do you sort with a custom comparator?

    Introsort in GCC's libstdc++ and MSVC (quicksort falling back to heapsort, insertion sort for small ranges), with O(n log n) guaranteed since C++11. It is not stable; use std::stable_sort for that.

    C++
    #include <algorithm>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        vector<pair<int, int>> intervals = {{5, 7}, {1, 3}, {2, 4}, {1, 2}};
        sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) {
            if (a.first != b.first) return a.first < b.first;
            return a.second < b.second;
        });
        for (auto& [s, e] : intervals) cout << "[" << s << "," << e << "] ";
        cout << "\n";
    }

    This prints [1,2] [1,3] [2,4] [5,7]. The comparator must be a strict weak ordering, so <= is undefined behavior. The quicksort visualization shows the partition step.

    Practice it: Merge Intervals, Non-overlapping Intervals

  11. What is the difference between push_back and emplace_back?

    push_back copies or moves an existing object into the vector. emplace_back takes constructor arguments and builds the element in place.

    C++
    #include <iostream>
    #include <vector>
    using namespace std;
    
    struct P {
        P(int, int) { cout << "ctor "; }
        P(const P&) { cout << "copy "; }
        P(P&&) noexcept { cout << "move "; }
    };
    
    int main() {
        vector<P> v;
        v.reserve(2);
        v.push_back(P(1, 2));
        v.emplace_back(3, 4);
        cout << "\n";
    }

    This prints ctor move ctor . The trap: emplace_back calls explicit constructors, so v.emplace_back(10) on a vector<vector<int>> adds a vector of ten zeros where push_back(10) would not compile.

  12. What does a std::set built from a vector with duplicates hold?

    C++
    #include <iostream>
    #include <set>
    #include <vector>
    using namespace std;
    
    int main() {
        vector<int> v = {3, 1, 3, 2, 1};
        set<int> s(v.begin(), v.end());
        cout << s.size() << " " << *s.begin() << " " << *s.rbegin() << "\n";
    }

    It prints 3 1 3. A std::set keeps one copy of each value and stays sorted, so it holds {1, 2, 3}, *s.begin() is 1 and *s.rbegin() is 3.

    When order does not matter, std::unordered_set gives O(1) average lookups instead of O(log n).

    Practice it: Contains Duplicate

  13. What are std::stack and std::queue, and what are container adaptors?

    std::stack (last in, first out) and std::queue (first in, first out) are container adaptors: they wrap another container, std::deque by default, and expose only push, pop, top or front, empty and size. They cannot be iterated, and pop() returns void, so read top() first.

    C++
    #include <iostream>
    #include <stack>
    #include <string>
    using namespace std;
    
    bool balanced(const string& s) {
        stack<char> st;
        for (char c : s) {
            if (c == '(' || c == '[' || c == '{') { st.push(c); continue; }
            if (st.empty()) return false;
            char open = st.top();
            st.pop();
            if ((c == ')' && open != '(') || (c == ']' && open != '[') || (c == '}' && open != '{'))
                return false;
        }
        return st.empty();
    }
    
    int main() {
        cout << balanced("{[()]}") << " " << balanced("([)]") << "\n";
    }

    This prints 1 0.

    Practice it: Valid Parentheses, Min Stack, Implement Queue Using Stacks

Coddy programming languages illustration

Learn to code with Coddy

Get started