cpp
vectors
01_vectors.cpp⚙️cpp
/**
* ============================================================
* C++ VECTORS (std::vector)
* ============================================================
*
* This file covers:
* - Vector basics
* - Adding and removing elements
* - Capacity and size
* - Iterators
* - Vector algorithms
* - 2D vectors
*
* Compile: g++ -std=c++17 -Wall 01_vectors.cpp -o vectors
* Run: ./vectors
*
* ============================================================
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric> // For accumulate
#include <string>
#include <iomanip>
using namespace std;
// Helper function to print vectors
template<typename T>
void printVector(const vector<T>& vec, const string& label = "") {
if (!label.empty()) cout << label << ": ";
cout << "[";
for (size_t i = 0; i < vec.size(); i++) {
cout << vec[i];
if (i < vec.size() - 1) cout << ", ";
}
cout << "]" << endl;
}
int main() {
cout << "============================================" << endl;
cout << " C++ VECTORS" << endl;
cout << "============================================" << endl << endl;
// ========================================================
// PART 1: VECTOR CREATION AND INITIALIZATION
// ========================================================
cout << "--- PART 1: CREATION & INITIALIZATION ---" << endl << endl;
// Empty vector
vector<int> empty;
// Vector with initial size (elements initialized to 0)
vector<int> sized(5);
// Vector with size and initial value
vector<int> filled(5, 10); // Five 10s
// Initialization list
vector<int> numbers = {1, 2, 3, 4, 5};
vector<string> fruits = {"apple", "banana", "cherry"};
// Copy constructor
vector<int> copy1(numbers);
// From array
int arr[] = {10, 20, 30, 40, 50};
vector<int> fromArray(arr, arr + 5);
// Range initialization
vector<int> range(numbers.begin() + 1, numbers.end() - 1); // {2, 3, 4}
// Display
printVector(empty, "empty");
printVector(sized, "sized(5)");
printVector(filled, "filled(5, 10)");
printVector(numbers, "numbers");
printVector(fruits, "fruits");
printVector(range, "range");
cout << endl;
// ========================================================
// PART 2: ACCESSING ELEMENTS
// ========================================================
cout << "--- PART 2: ACCESSING ELEMENTS ---" << endl << endl;
vector<int> v = {10, 20, 30, 40, 50};
// Using [] operator (no bounds checking)
cout << "v[0] = " << v[0] << endl;
cout << "v[2] = " << v[2] << endl;
// Using at() (with bounds checking - throws exception)
cout << "v.at(1) = " << v.at(1) << endl;
// Front and back
cout << "v.front() = " << v.front() << endl;
cout << "v.back() = " << v.back() << endl;
// Data pointer (access underlying array)
int* ptr = v.data();
cout << "*(v.data()) = " << *ptr << endl;
cout << "*(v.data() + 2) = " << *(ptr + 2) << endl;
// Modify elements
v[0] = 100;
v.at(1) = 200;
printVector(v, "After modification");
// ⚠️ Bounds checking example
try {
cout << v.at(10) << endl; // Throws out_of_range
} catch (const out_of_range& e) {
cout << "Exception: " << e.what() << endl;
}
cout << endl;
// ========================================================
// PART 3: SIZE AND CAPACITY
// ========================================================
cout << "--- PART 3: SIZE AND CAPACITY ---" << endl << endl;
vector<int> vec;
cout << "Empty vector:" << endl;
cout << " size(): " << vec.size() << endl;
cout << " capacity(): " << vec.capacity() << endl;
cout << " empty(): " << boolalpha << vec.empty() << endl;
cout << " max_size(): " << vec.max_size() << endl;
// Add elements and watch capacity grow
cout << "\nAdding elements:" << endl;
for (int i = 1; i <= 10; i++) {
vec.push_back(i);
cout << " After adding " << i << ": size=" << vec.size()
<< ", capacity=" << vec.capacity() << endl;
}
// Reserve capacity (avoid reallocations)
vector<int> reserved;
reserved.reserve(100); // Pre-allocate space
cout << "\nAfter reserve(100):" << endl;
cout << " size(): " << reserved.size() << endl;
cout << " capacity(): " << reserved.capacity() << endl;
// Resize
vector<int> resized(5, 1);
printVector(resized, "Original");
resized.resize(8, 0); // Expand with 0s
printVector(resized, "After resize(8, 0)");
resized.resize(3); // Shrink
printVector(resized, "After resize(3)");
// Shrink capacity to fit size
vector<int> bloated(100);
bloated.resize(5);
cout << "\nBefore shrink_to_fit: capacity=" << bloated.capacity() << endl;
bloated.shrink_to_fit();
cout << "After shrink_to_fit: capacity=" << bloated.capacity() << endl;
cout << noboolalpha << endl;
// ========================================================
// PART 4: ADDING AND REMOVING ELEMENTS
// ========================================================
cout << "--- PART 4: MODIFYING VECTORS ---" << endl << endl;
vector<int> data = {1, 2, 3};
printVector(data, "Initial");
// push_back - add to end
data.push_back(4);
data.push_back(5);
printVector(data, "After push_back(4, 5)");
// emplace_back - construct in place (more efficient)
data.emplace_back(6);
printVector(data, "After emplace_back(6)");
// pop_back - remove from end
data.pop_back();
printVector(data, "After pop_back()");
// insert - add at position
data.insert(data.begin() + 2, 100); // Insert at index 2
printVector(data, "After insert at index 2");
// Insert multiple elements
data.insert(data.end(), {7, 8, 9});
printVector(data, "After insert {7,8,9} at end");
// erase - remove at position
data.erase(data.begin() + 2); // Remove element at index 2
printVector(data, "After erase at index 2");
// Erase range
data.erase(data.begin() + 4, data.end()); // Remove from index 4 to end
printVector(data, "After erase range");
// clear - remove all elements
vector<int> toClear = {1, 2, 3};
toClear.clear();
cout << "After clear(): size=" << toClear.size() << endl;
// assign - replace all elements
vector<int> toAssign;
toAssign.assign(5, 42);
printVector(toAssign, "After assign(5, 42)");
toAssign.assign({10, 20, 30});
printVector(toAssign, "After assign({10,20,30})");
cout << endl;
// ========================================================
// PART 5: ITERATORS
// ========================================================
cout << "--- PART 5: ITERATORS ---" << endl << endl;
vector<int> nums = {10, 20, 30, 40, 50};
// Using iterators
cout << "Forward iteration: ";
for (vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// Using auto (cleaner)
cout << "With auto: ";
for (auto it = nums.begin(); it != nums.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// Reverse iteration
cout << "Reverse: ";
for (auto it = nums.rbegin(); it != nums.rend(); ++it) {
cout << *it << " ";
}
cout << endl;
// Const iterators (read-only)
cout << "Const iterator: ";
for (auto it = nums.cbegin(); it != nums.cend(); ++it) {
cout << *it << " ";
// *it = 100; // ERROR: can't modify through const iterator
}
cout << endl;
// Iterator arithmetic
auto start = nums.begin();
auto finish = nums.end();
cout << "Distance: " << distance(start, finish) << endl;
cout << "Third element: " << *(start + 2) << endl;
// Modifying through iterator
for (auto it = nums.begin(); it != nums.end(); ++it) {
*it *= 2;
}
printVector(nums, "After doubling");
cout << endl;
// ========================================================
// PART 6: ALGORITHMS WITH VECTORS
// ========================================================
cout << "--- PART 6: ALGORITHMS ---" << endl << endl;
vector<int> values = {64, 34, 25, 12, 22, 11, 90};
printVector(values, "Original");
// Sort
sort(values.begin(), values.end());
printVector(values, "Sorted ascending");
sort(values.begin(), values.end(), greater<int>());
printVector(values, "Sorted descending");
// Sort again for other algorithms
sort(values.begin(), values.end());
// Binary search (requires sorted vector)
bool found = binary_search(values.begin(), values.end(), 25);
cout << "binary_search(25): " << boolalpha << found << endl;
// Find
auto it = find(values.begin(), values.end(), 34);
if (it != values.end()) {
cout << "Found 34 at index: " << distance(values.begin(), it) << endl;
}
// Count
values.push_back(25);
int cnt = count(values.begin(), values.end(), 25);
cout << "Count of 25: " << cnt << endl;
// Min and Max
auto minIt = min_element(values.begin(), values.end());
auto maxIt = max_element(values.begin(), values.end());
cout << "Min: " << *minIt << ", Max: " << *maxIt << endl;
// Sum (accumulate)
int sum = accumulate(values.begin(), values.end(), 0);
cout << "Sum: " << sum << endl;
// Reverse
reverse(values.begin(), values.end());
printVector(values, "Reversed");
// Remove-erase idiom
vector<int> withDups = {1, 2, 2, 3, 3, 3, 4};
withDups.erase(remove(withDups.begin(), withDups.end(), 3), withDups.end());
printVector(withDups, "After removing 3s");
// Unique (remove consecutive duplicates - sort first!)
vector<int> dups = {1, 1, 2, 2, 3, 3, 3};
dups.erase(unique(dups.begin(), dups.end()), dups.end());
printVector(dups, "After unique");
cout << noboolalpha << endl;
// ========================================================
// PART 7: 2D VECTORS
// ========================================================
cout << "--- PART 7: 2D VECTORS ---" << endl << endl;
// Creating 2D vector
vector<vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Display
cout << "2D Vector (Matrix):" << endl;
for (const auto& row : matrix) {
for (int val : row) {
cout << setw(3) << val;
}
cout << endl;
}
// Access elements
cout << "matrix[1][2] = " << matrix[1][2] << endl;
// Create 3x4 matrix filled with zeros
int rows = 3, cols = 4;
vector<vector<int>> grid(rows, vector<int>(cols, 0));
cout << "\n3x4 Grid initialized to 0:" << endl;
for (const auto& row : grid) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
// Add row
grid.push_back({1, 1, 1, 1});
cout << "\nAfter adding a row:" << endl;
for (const auto& row : grid) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
// Jagged array (rows of different sizes)
vector<vector<int>> jagged = {
{1},
{2, 3},
{4, 5, 6},
{7, 8, 9, 10}
};
cout << "\nJagged array:" << endl;
for (const auto& row : jagged) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
cout << endl;
// ========================================================
// PART 8: VECTOR vs ARRAY COMPARISON
// ========================================================
cout << "--- PART 8: VECTOR vs ARRAY ---" << endl << endl;
cout << "┌────────────────┬───────────────┬───────────────┐" << endl;
cout << "│ Feature │ Array │ Vector │" << endl;
cout << "├────────────────┼───────────────┼───────────────┤" << endl;
cout << "│ Size │ Fixed │ Dynamic │" << endl;
cout << "│ Memory │ Stack/Static │ Heap │" << endl;
cout << "│ Bounds check │ No │ at() method │" << endl;
cout << "│ Size info │ Manual │ size() │" << endl;
cout << "│ Pass to func │ Decays │ By reference │" << endl;
cout << "│ Performance │ Slightly faster│ Slight overhead│" << endl;
cout << "└────────────────┴───────────────┴───────────────┘" << endl;
cout << "\n💡 Recommendation: Use std::vector by default!" << endl;
cout << endl;
cout << "============================================" << endl;
cout << "VECTOR SUMMARY:" << endl;
cout << "============================================" << endl;
cout << "• Dynamic resizing" << endl;
cout << "• Rich API for manipulation" << endl;
cout << "• Works with STL algorithms" << endl;
cout << "• Bounds checking with at()" << endl;
cout << "• Contiguous memory storage" << endl;
cout << "============================================" << endl;
return 0;
}
// ============================================================
// EXERCISES:
// ============================================================
/*
* 1. Implement a function to remove all duplicates from a vector
*
* 2. Write a program that reads numbers until -1 is entered,
* stores them in a vector, and displays statistics
*
* 3. Implement merge sort using vectors
*
* 4. Create a sparse matrix representation using 2D vectors
*
* 5. Write a function to rotate a 2D vector (matrix) 90 degrees
*/