VECTORS IN C++

In classic arrays in C++ (e.g. int arr[10]), the size must be defined in advance and cannot be changed during program execution.

However, in real-world problems we often do not know in advance how much data we will need to store.

This is where std::vector comes in — a data structure that behaves like an array, but can automatically grow and shrink in size.

A generic container of objects of the same type that is an alternative to C++ fields. In other words, they are dynamic lists. Unlike arrays whose dimension does not change, with vectors it can change dynamically.​​ The array declaration is:​
int arr[3]={4,2,7}
​

Here, the dimensions (3) must be specified in square brackets and cannot be changed further.
Unlike a sheet, the dimension of a vector can be changed during the program.

Include header file: vector

​In order to be able to use a vector in our program, it needs to be included using the directive #include:
#include <vector>
​The following line should be added below that, which defines the use of the std namespace:

using namespace std;

Otherwise, you would have to write std::vector every time you want to call a vector
Example of vector usage:
#include <vector>
using namespacestd;
vector<int>a(10);
This is the declaration of a vector whose data is of type int
Here is: Accessing the elements of a vector is similar to that of arrays. For example. We would approach the 3rd member of the vector as follows:
a[3]
​

Basic Manipulation of std::vector in C++


This example demonstrates how to use std::vector as a dynamic array in C++.

You will see how to add elements using push_back(), iterate through elements using a range-based loop, and get the number of elements with size().



#include <iostream>   // for input/output (cout)
#include <vector>     // for std::vector

using namespace std;

int main() {

    // Creating an empty vector of integers
    vector<int> numbers;

    // Adding elements to the vector (dynamic resizing happens automatically)
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);

    // Printing vector elements using range-based for loop
    cout << "Vector elements: ";
    for (int num : numbers) {
        cout << num << " ";
    }

    // Printing the number of elements in the vector
    cout << "\nVector size: " << numbers.size() << endl;

    return 0;
}
        

Vector methods in C++

​Some of the methods for working with vectors in c++:

Adding an element to the end of a vector

Method push_back
example of adding the number 13 to the end of vector a:
a.push_back(13);

Vector size in c++

The size of the vector can be determined by the method. Usage example:

Getting the Number of Elements in a Vector


This example shows how to determine the number of elements stored in a std::vector using the size() method.



#include <iostream>   // for cout
#include <vector>     // for std::vector

using namespace std;

int main() {

    // Initializing a vector with 5 elements
    vector<int> b = {10, 20, 30, 40, 50};

    // Printing the number of elements in the vector
    cout << "Number of elements in the vector is "
         << b.size()
         << "." << endl;

    return 0;
}
        

Taking the first element from a vector

The first element of the vector can be obtained by the method​ vector::front().

Accessing the First Element of a Vector


This example demonstrates how to access the first element of a std::vector using the front() function.



#include <iostream>   // for cout
#include <vector>     // for std::vector
#include <string>     // for std::string

using namespace std;

int main() {

    // Initializing a vector of strings
    vector<string> groups = {"Michael", "Peter", "Lazar", "Natasha"};

    // Accessing the first element of the vector
    cout << "The first in the group is "
         << groups.front()
         << endl;

    return 0;
}
        

The front() function returns the first element in the vector. It is important to note that the vector must not be empty when calling this function.

The output would show: Michael

​Retrieving the last element in a vector

The last element can be retrieved from the vector using the method vector::back(). For example. in the previous group vector example, the last a group member would be:

Accessing the Last Element of a Vector


This example demonstrates how to access the last element of a std::vector using the back() function.



#include <iostream>   // for cout
#include <vector>     // for std::vector
#include <string>     // for std::string

using namespace std;

int main() {

    // Initializing a vector of strings
    vector<string> group = {"Michael", "Peter", "Lazar", "Natasha"};

    // Accessing the last element of the vector
    cout << "The last one in the group is "
         << group.back()
         << endl;

    return 0;
}

The back() function returns the last element in the vector. Make sure the vector is not empty before calling back(), otherwise the behavior is undefined.

The output would show: Natasha

Inserting a value at a specific position in a vector

Suppose an arbitrary dynamic sequence of numbers is given:​
vector < int > numbers={0, 4, 11, 6};
If we want e.g. to replace the new number 5 with the existing number 11, which is in position 2 in the sequence, we can do it as follows:​
numbers[2] = 5;
or using the at function:
numbers.at(2) = 5;
The array after modification would look like:​
{0, 4, 5, 6};
It can be observed that in this way the value that was previously in the inserted position is deleted. If we want to keep the previous element and insert a new one, then the insert function should be used. For example, if we wanted to now add the value 3 to position 1, then we could do it like this:​
int pos = 1;
auto itr=numbers.begin() + pos;
numbers.insert(itr, 3);
After that the array would look like
{0, 3, 4, 5, 6};
We can see that the value 3 has been inserted in position 1 and the value 4 which was previously in that position has moved to position 2.
A array of values ​​can also be added to a specific position. For example. if at position 3 now, we want to insert the following array:
{11, 12, 13};
they would do it like this:
int pos = 3;
auto itr=numbers.begin() + pos;
numbers.insert(itr, {11, 12, 13});
The string after insertion would look like:
{0, 3, 4, 5, 11, 12, 13, 6};

Deleting the last element of the vector

​The last element of the vector can be deleted by the method​ vector::pop_back
The following example shows the application of this method:

Removing the Last Element from a Vector


This example shows how to remove the last element from a std::vector using the pop_back() function.



#include <iostream>     // for cout
#include <vector>       // for std::vector

using namespace std;

int main() {

    // Initializing a vector of double values (temperatures)
    vector<double> temperatures = {23.2, 25.8, 11, 15.3, 17};

    // Print original vector
    cout << "Original temperatures: ";
    for(double t : temperatures) {
        cout << t << " ";
    }
    cout << endl;

    // Remove the last element
    temperatures.pop_back();

    // Print vector after removing last element
    cout << "After pop_back(): ";
    for(double t : temperatures) {
        cout << t << " ";
    }
    cout << endl;

    return 0;
}

The pop_back() function removes the last element of the vector. Make sure the vector is not empty before calling pop_back(), otherwise the behavior is undefined.

After this command the vector values ​​are:​ 23.2, 25.8, 11, 15.3

​Deleting a vector element at a specific position

vector::erase(it) will delete the element of the vector pointed to by the iterator it
Example:

Deleting an Element from a Vector using erase()


This example demonstrates how to delete a specific element from a std::vector using the erase() function.



#include <iostream>     // for cout
#include <vector>       // for std::vector

using namespace std;

int main() {

    // Initialize a vector with three elements
    vector<int> c = {2, 3, 4};

    // Print original vector
    cout << "Original vector: ";
    for(int num : c) {
        cout << num << " ";
    }
    cout << endl;

    // Delete the element at position 1 (second element)
    c.erase(c.begin() + 1);  // removes the value 3

    // Print vector after deletion
    cout << "After erase(): ";
    for(int num : c) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

The erase() function removes the element at the specified position. Note that vector indices start at 0, so c.begin() + 1 refers to the second element. All subsequent elements are shifted one position to the left.

After deletion, the elements of the vector are:​ 2, 4

Deleting all vector elements in c++

If we want to empty the vector, ie. to delete all its elements we can use the method​ vector::clear()
Usage example:
#include < vector >
using namespacestd;
vector < int > c={2,3,4};
c.clear();//deletes all elements in the vector
​After this, the vector will be empty

Printing the elements of a vector

Let the following vector be given:
#include < vector >
using namespacestd;
vector < int > numbers={1,2,3,4,5};
Example of printing numbers to standard output:
for(int i = 0; i < brojevi.size(); i++)
{
cout << numbers[i] << " ";
}
cout << endl;
​On the output: 1 2 3 4 5

Test your code here!

// Write your C++ code here...

Reading text data from standard input and inserting one by one into a vector

The <string> header must also be included. Using a while loop, one word at a time is loaded and added to the vector:
#include <vector>
#include <iostream>
#include <string>

using namespacestd;

// Declare a vector of strings to store the input words
vector<string> text;

// Variable to hold each word from input
string word;

// Read words from standard input until EOF or an error occurs
while(cin >> word)
{
// Add each word to the vector
text.push_back(word);
}

​Iterating through the elements of a vector using an iterator []

​In order to print the words entered into the vector in the previous example on the standard output, the following code must be executed:
cout << "Words in the text::\n" << endl;
for(int i = 0; i < text.size(); i++)
{
cout << text[i] << " ";
}
cout << endl;

​Iterating through the elements of a vector using an iterator

​The following code demonstrates the use of an iterator to loop through the elements of a vector
#include < vector >
using namespacestd;
vector < int > points={5,3,5,7,8,2,3,4};
cout << "Number of points per task:\n " << endl;
for(vector < int >::iterator it=points.begin(); it != points.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
​The following functions are also implemented in the previous code:
​
v.begin() – returns an iterator pointing to the initial element of the container​
v.end() – returns an iterator pointing "behind the last" element of the container.

Sorting vectors in c++ with the sort library function

The sort function is located in the <algorithm> header, which must be included at the beginning of the file.
#include < algorithm >
​The parameters to be passed are pointers to the first and last element to be sorted in the array. If it is necessary to sort the entire array then the code would be as in the following example:
#include < vector >
using namespacestd;
vector < int > A={4,2,7,5,9};
sort(A.begin(),A.end());
//printing

Important std::vector Methods


Vectors in C++ provide many useful methods for managing dynamic arrays. Below are the basic methods, along with examples demonstrating their usage.


Basic Methods


Method Description
push_back() Adds an element to the end of the vector.
pop_back() Removes the last element from the vector.
size() Returns the number of elements in the vector.
clear() Deletes all elements from the vector.
at() Accesses an element at a specified index with bounds checking.

Examples of Method Usage


1. Adding Elements – push_back()

The push_back() method is used for dynamically adding elements to a vector.


#include<iostream>#include<vector>int main() {
    std::vector<int> numbers;
    numbers.push_back(10); // Adds 10
    numbers.push_back(20); // Adds 20std::cout << numbers[0] << ", " << numbers[1] << "\n";

    return 0;
}
        

2. Removing Elements – pop_back()


The pop_back() method removes the last element from the vector.


#include<iostream>#include<vector>int main() {
    std::vector<int> numbers = {10, 20, 30};
    numbers.pop_back(); // Removes 30std::cout << numbers.size() << "\n"; // Prints 2return 0;
}
        

3. Getting Size – size()


The size() method returns the number of elements in the vector.


#include<iostream>#include<vector>int main() {
    std::vector<int> numbers = {1, 2, 3, 4};
    std::cout << "Vector size: " << numbers.size() << "\n";

    return 0;
}
        

4. Deleting All Elements – clear()


The clear() method removes all elements from the vector, leaving it empty.


#include<iostream>#include<vector>int main() {
    std::vector<int> numbers = {1, 2, 3};
    numbers.clear();
    
    std::cout << "Vector is empty: " << numbers.size() << "\n";

    return 0;
}
        

5. Accessing Elements – at()

The at() method allows access to an element with bounds checking.


#include<iostream>#include<vector>int main() {
    std::vector<int> numbers = {5, 10, 15};
    std::cout << numbers.at(1) << "\n"; // Accesses element at index 1return 0;
}
        

More Detailed Code Examples

To better understand the practical use of std::vector in C++, here are some examples showing declaration, initialization, and manipulation of vectors.

Declaration and Initialization of Vectors

Below is an example of basic vector declaration and initialization:


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    for (int number : numbers) {
        std::cout << number << " ";
    }
    
    return 0;
}
        

In this example, the vector numbers is initialized with five elements and printed in a loop.

Adding and Removing Elements

Vectors allow dynamic addition and removal of elements using the push_back and pop_back methods:


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;
    
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);
    
    std::cout << "The vector contains: ";
    for (int number : numbers) {
        std::cout << number << " ";
    }
    
    numbers.pop_back(); // Removes the last element
    
    std::cout << "\nAfter pop_back: ";
    for (int number : numbers) {
        std::cout << number << " ";
    }

    return 0;
}
        

With this approach, we can easily add and remove elements from the vector without manually managing memory.

Iteration and Accessing Elements

We can use indexing or an iterator to traverse the vector:


#include <iostream>
#include <vector>
#include <string>

int main() {
    std::vector<std::string> names = {"Anna", "Mark", "John"};

    for (size_t i = 0; i < names.size(); i++) {
        std::cout << names[i] << " ";
    }
    
    std::cout << "\nUsing iterator: ";
    for (auto it = names.begin(); it != names.end(); ++it) {
        std::cout << *it << " ";
    }
    
    return 0;
}
        

This approach demonstrates different ways to traverse a vector – using classic indexing and an iterator.

Conclusion

Vectors in C++ provide a flexible and efficient alternative to static arrays, offering dynamic allocation and useful methods for working with data. By understanding these basic operations, developers can efficiently manage arrays of data in their applications.

Advanced Features

Vectors in the C++ standard library offer a wide range of methods for data manipulation. This section covers advanced topics such as iteration, adding, and removing elements using push_back, insert, and erase, as well as the difference between size and capacity.

Iterating Through a Vector

There are multiple ways to iterate through a vector – using classic indexing, a range-based for loop, and iterators:


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {10, 20, 30, 40, 50};

    std::cout << "Classic indexing: ";
    for (size_t i = 0; i < numbers.size(); i++) {
        std::cout << numbers[i] << " ";
    }

    std::cout << "\nRange-based for loop: ";
    for (int number : numbers) {
        std::cout << number << " ";
    }

    std::cout << "\nIterator: ";
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }

    return 0;
}
    

Adding and Inserting Elements

Besides push_back, which adds an element to the end of the vector, we can use insert to insert elements at arbitrary positions.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {10, 20, 30};

    numbers.push_back(40); // Adds 40 to the end
    numbers.insert(numbers.begin() + 1, 15); // Inserts 15 at the second position

    std::cout << "Vector after insertion: ";
    for (int number : numbers) {
        std::cout << number << " ";
    }

    return 0;
}
    

Removing Elements

The erase method is used to remove individual elements or a range of elements from a vector.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {10, 20, 30, 40, 50};

    numbers.erase(numbers.begin() + 2); // Removes the third element (30)
    numbers.erase(numbers.begin(), numbers.begin() + 2); // Removes the first two values

    std::cout << "Vector after removal: ";
    for (int number : numbers) {
        std::cout << number << " ";
    }

    return 0;
}
    

Difference Between size and capacity

The size() method returns the number of elements in the vector, while capacity() indicates how many elements can fit in the currently allocated space.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;

    std::cout << "Initial size: " << numbers.size()
              << ", capacity: " << numbers.capacity() << "\n";

    numbers.push_back(1);
    numbers.push_back(2);
    numbers.push_back(3);

    std::cout << "After adding elements: " << numbers.size()
              << ", capacity: " << numbers.capacity() << "\n";

    return 0;
}
    

Comparison with Other Containers

The C++ Standard Library offers multiple containers for data storage, with the most commonly used being std::vector, std::array, and std::list. Each of them has specific characteristics that make them suitable for particular situations.

Comparison of Key Features

Feature std::vector std::array std::list
Size Dynamic, can grow Fixed, determined at creation Dynamic
Access Speed O(1) – direct access via indexing O(1) – direct access via indexing O(n) – the list must be traversed to reach the desired element
Adding/Removing Elements Efficient at the end (O(1)), slow at the beginning and in the middle (O(n)) Not possible (fixed size) Efficient anywhere (O(1)), but without direct access
Internal Structure Memory array, elements are stored sequentially Static array, elements are stored sequentially Linked list, each element contains pointers to the next/previous

When to Use Which Container?

  • std::vector: When dynamic size and fast indexed access are needed.
  • std::array: When the array size is known and minimal overhead is required.
  • std::list: When frequent insertions or deletions at the beginning/middle of the structure are necessary.

Practical Examples

1. Using std::vector

std::vector is excellent when elements need to be dynamically added.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3};
    numbers.push_back(4); // Adds an element to the end
    std::cout << "Third element: " << numbers[2] << "\n"; // O(1) access

    return 0;
}
        

2. Using std::array

std::array is a static array that uses stack memory, making it faster when the size is known.


#include <iostream>
#include <array>

int main() {
    std::array<int, 3> numbers = {10, 20, 30};
    std::cout << "First element: " << numbers[0] << "\n"; // O(1) access

    return 0;
}
        

3. Using std::list

std::list is useful when frequent insertion or deletion at any position is needed.


#include <iostream>
#include <list>

int main() {
    std::list<int> numbers = {10, 20, 30};
    numbers.push_front(5); // Adds 5 to the beginning
    numbers.erase(numbers.begin()); // Removes the first element

    std::cout << "First element after removal: " << *numbers.begin() << "\n";

    return 0;
}
        

Conclusion

The choice between std::vector, std::array, and std::list depends on program needs. If fast element access and dynamic growth are required, std::vector is the best choice. If a fixed size with minimal memory overhead is needed, use std::array. If frequent additions and deletions from various positions are necessary, std::list is the better option.

Discussion on Efficiency and Usage

Vectors in C++ have many advantages compared to static arrays, especially when working with dynamic data. However, their usage comes with certain trade-offs. Below, the advantages and potential drawbacks of vectors are explained, along with examples for better understanding.

Advantages of Vectors


Feature Description
Dynamic Size Vectors automatically adjust their size based on the number of elements, unlike static arrays with a fixed size.
Ease of Use Vectors come with built-in methods for adding, removing, and searching elements.
Safety Methods like at() allow bounds checking, preventing access to non-existent elements.

Example: Dynamic Expansion


One of the biggest advantages of vectors is automatic expansion, which allows working with an unknown number of elements during program execution.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;
    for (int i = 1; i <= 10; ++i) {
        numbers.push_back(i); // Dynamically adds numbers from 1 to 10
    }

    for (int number : numbers) {
        std::cout << " " << number << " ";
    }

    return 0;
}
        

Disadvantages of Vectors


Feature Description
Memory Preallocation Vectors allocate extra memory to reduce reallocation frequency, which can lead to inefficient memory usage.
Performance When a vector expands, reallocation of elements is required, which can be costly in terms of execution time.

Example: Reallocation Effect


When a vector expands, new memory is allocated, and existing elements are copied to the new location. This can cause performance degradation in cases of frequent element additions.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;
    for (int i = 1; i <= 100000; ++i) {
        numbers.push_back(i); // Frequent expansion due to element additions
    }

    std::cout << "Total number of elements: " << numbers.size() << "\n";

    return 0;
}
        

Conclusion

Vectors are ideal for scenarios where the size of data is variable, as they simplify working with dynamic structures. However, it is essential to consider their limitations, such as potential inefficiencies in memory usage and performance in cases of frequent expansions. In such situations, it may be better to consider other data structures, such as std::deque or std::list.

Advanced Topics

In addition to basic operations, vectors in C++ allow working with advanced concepts such as iterators, the difference between capacity and size, and working with 2D vectors (vectors of vectors). These topics are essential for advanced handling of dynamic data structures in more complex scenarios.

1. Iterators for Traversing a Vector

Iterators provide a flexible and efficient way to traverse vector elements, offering control over elements without directly using indices.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << "Element: " << *it << "\n";
    }

    return 0;
}
        

Iterators are used with functions like begin() and end(), where *it accesses the value at the iterator's current position.

2. Difference Between Capacity and Size

Size (size()) represents the current number of elements in the vector, while capacity (capacity()) indicates how many elements the vector can hold before memory reallocation occurs.


#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;
    numbers.push_back(10);
    numbers.push_back(20);

    std::cout << "Size: " << numbers.size() 
              << ", Capacity: " << numbers.capacity() << "\n";

    numbers.reserve(100); // Reserves space for 100 elements

    std::cout << "Capacity after reserve: " << numbers.capacity() << "\n";

    return 0;
}
        

Reserving capacity in advance can improve performance when a large number of additional elements is expected.

3. Working with 2D Vectors (Vectors of Vectors)

Vectors of vectors allow working with matrices or tabular data. Each element of the main vector can be another vector, creating a structure similar to a 2D array.


#include <iostream>
#include <vector>

int main() {
    std::vector<std::vector<int>> matrix = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    std::cout << "Element [0][1]: " << matrix[0][1] << "\n";

    for (int i = 0; i < matrix.size(); ++i) {
        for (int j = 0; j < matrix[i].size(); ++j) {
            std::cout << matrix[i][j] << " ";
        }
        std::cout << "\n";
    }

    return 0;
}
        

Vectors of vectors are more flexible than traditional 2D arrays, as each "row" can have a different number of columns.

Conclusion

These advanced topics provide significant flexibility when working with data in C++. Understanding iterators, the difference between capacity and size, and working with multidimensional structures allows for efficient use of vectors in more complex scenarios.

Practical Exercises


To better understand the use of vectors in C++, we suggest several simple exercises for practice. These exercises cover input and processing of vector elements, as well as the application of basic methods and loops.


1. Entering n numbers and printing them in reverse order

Task: Allow the user to enter n numbers into a vector and then print those numbers in reverse order.



#include <iostream>
#include <vector>

int main() {
    int n;
    std::cout << "Enter the number of elements: ";
    std::cin >> n;

    std::vector<int> numbers(n);
    for (int i = 0; i < n; ++i) {
        std::cout << "Enter number " << i + 1 << ": ";
        std::cin >> numbers[i];
    }

    std::cout << "Numbers in reverse order:\n";
    for (int i = n - 1; i >= 0; --i) {
        std::cout << numbers[i] << " ";
    }
    std::cout << "\n";

    return 0;
}
        

2. Filtering even numbers from a vector

Task: Enter a sequence of numbers and extract all even numbers into a new vector.



#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8};
    std::vector<int> evenNumbers;

    for (int number : numbers) {
        if (number % 2 == 0) {
            evenNumbers.push_back(number);
        }
    }

    std::cout << "Even numbers:\n";
    for (int number : evenNumbers) {
        std::cout << number << " ";
    }
    std::cout << "\n";

    return 0;
}
        

3. Calculating the average of elements

Task: Enter a sequence of numbers and calculate their average.



#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {10, 20, 30, 40, 50};
    int sum = 0;

    for (int number : numbers) {
        sum += number;
    }

    double average = static_cast<double>(sum) / numbers.size();
    std::cout << "Average: " << average << "\n";

    return 0;
}
        

Conclusion

These exercises provide practical examples for understanding basic vector operations, such as input, filtering, and aggregation. It is recommended to extend the exercises further for practice, for example, by adding input validation or working with larger data sets.

Adding Resources


To further expand your knowledge of vectors and their usage in C++, we recommend the following resources. These materials cover both basic and advanced topics, providing theoretical foundations and practical examples.


1. Official Documentation

The official documentation of the C++ standard library provides detailed information on all vector functions and methods, along with usage examples. It is recommended for precise and reliable information.


2. Online Courses

If you prefer an interactive learning approach, the following online courses provide in-depth lessons on working with vectors and other concepts in C++:


3. Relevant Books

Books on C++ programming often include extensive information on vectors. Here are some recommended titles for different knowledge levels:

  • "The C++ Programming Language" - Bjarne Stroustrup (creator of C++)
  • "Effective Modern C++" - Scott Meyers (an excellent guide to modern C++)
  • "C++ Primer" - Stanley B. Lippman, Josée Lajoie, Barbara E. Moo (a great book for beginners and intermediate learners)

4. Guides and Tutorials

The following tutorials and guides provide practical instructions and examples:


5. Discussions and Communities

Participating in communities and forums can help you solve specific problems and learn from others. Recommended communities:


Conclusion

Learning from various resources provides a broad spectrum of knowledge and helps in understanding how vectors are used in real-world projects. A combination of theory, practical exercises, and community engagement is recommended for a comprehensive grasp of this topic.