The vectors are sequence containers to store data of a similar type. Vectors represent arrays that can change in size. Just like arrays, vectors use contiguous storage locations for their elements, which means that their elements can also be accessed using offsets on regular pointers to their elements, and just as efficiently as in arrays. But unlike arrays, their size can change dynamically, with their storage being handled automatically by the container.
Internally, vectors use a dynamically allocated array to store their elements. This array may need to be reallocated in order to grow in size when new elements are inserted, which implies allocating a new array and moving all elements to it. This is a relatively expensive task in terms of processing time, and thus, vectors do not reallocate each time an element is added to the container. Instead, vector containers may allocate some extra storage to accommodate for possible growth, and thus the container may have an actual capacity greater than the storage strictly needed to contain its elements (i.e., its size).
Libraries can implement different strategies for growth to balance between memory usage and reallocations, but in any case, reallocations should only happen at logarithmically growing intervals of size so that the insertion of individual elements at the end of the vector can be provided with amortized constant time complexity.
Therefore, compared to arrays, vectors consume more memory in exchange for the ability to manage storage and grow dynamically in an efficient way.
Declaration
To use a vector in a C++ program, one needs to include the vector library:
#include <vector>
The syntax of the declaration of a vector is as follows:
vector <data_type> vector_var;
Where, data_type
can be any valid primary, secondary or user-defined data type permitted by C++. The data type can be a vector itself.
Example:
vector <int> whole_numbers;
The above example just declares the vector but the size of the vector is 0. The size of the vector can also be mentioned at the time of declaration. The syntax for the same is as follows:
vector <data_type> vector_var (size);
Where size should be strictly an unsigned integer.
Example:
vector <int> whole_numbers (10);
The advantage of mentioning the size at the time of declaration is that it is efficient to allocate memory at compile time and also, all the 10 values of the vector whole_numbers
in the above declaration will be initialised to 0. The vector library provides a method size()
which returns the number of values the vector object holds.
Example 1
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> whole_numbers;
cout << "The size of the vector 'whole_numbers' is "
<< whole_numbers.size();
return 0;
}
Output: The size of the vector ‘whole_numbers’ is 0
Conclusion: If the size is not mentioned, the default size is 0
Example 2
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> whole_numbers (10);
cout << "The size of the vector 'whole_numbers' is "
<< whole_numbers.size();
return 0;
}
Output: The size of the vector ‘whole_numbers’ is 10
Conclusion: The vector gets declared and the mentioned size is allocated to the vector.
Example 3
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> whole_numbers (10);
cout << "The size of the vector 'whole_numbers' is "
<< whole_numbers.size() << endl;
cout << "The elements in the vector are: ";
for (size_t i = 0 ; i < whole_numbers.size() ; i++)
cout << whole_numbers[i] << " ";
return 0;
}
Output:
The size of the vector 'whole_numbers' is 10
The elements in the vector are: 0 0 0 0 0 0 0 0 0 0
Conclusion: If just the size is mentioned, all the values in the vector will be initialized to 0
Initialising vectors
Using initializer lists
When the values to be present in the vector are known at the time of declaration, the following syntax can be used:
Syntax:
vector <data_type> vector_var {value_1, value_2,..., value_n};
// Or
vector <data_type> vector_var = {value_1, value_2,..., value_n};
// Or
vector <data_type> vector_var = ({value_1, value_2,..., value_n});
Where the values being initialised are strictly of the type data_type
.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <char> vowels = {'a', 'e', 'i', 'o', 'u'};
for (size_t i = 0 ; i < vowels.size() ; i++)
cout << vowels[i] << " ";
return 0;
}
Output: a e i o u
Conclusion: Vector initialisation using initialiser lists
Using constructor of vector container
When the value to be present in all n
indices of the vector is known, one can use the following syntax:
vector <data_type> vector_var (len, val);
The above syntax declares a vector named vector_var of size len
and all the indices will be initialized to val
.
Example:
vector <int> max_marks (10, 50);
The above syntax declares a vector named max_marks
of size 10 and initializes all 10 indices to the value 50.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> whole_numbers (10, 10);
cout << "The size of the vector 'whole_numbers' is "
<< whole_numbers.size() << endl;
cout << "The elements in the vector are: ";
for (size_t i = 0 ; i < whole_numbers.size() ; i++)
cout << whole_numbers[i] << " ";
return 0;
}
Output:
The size of the vector 'whole_numbers' is 10
The elements in the vector are: 10 10 10 10 10 10 10 10 10 10
Conclusion: If the size and the value is mentioned, all the values in the vector will be initialized accordingly.
Using another vector
A new vector can be initialised with another vector. All the values of the source vector will be deep copied to the newly declared vector. The following is the syntax:
vector <data_type> vector_var (src_vector);
Where the src_vector
strictly contains the values of the same data_type
as that of the new vector. Any changes made to vector_var
are local to vector_var
and don’t reflect in src_vector
.
Accessing values of a vector
Using subscripts – [ ]
Accessing vector elements could be done similar to accessing array elements – through subscripts. The syntax to do so is as follows:
vector_var[index];
Where the index is strictly unsigned integer which should be between 0 and size - 1
inclusive.
Array accessing using the subscripts provides no bound checking. That is, the programmer can mention an index value greater than size - 1
. This causes the return value to be garbage.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> whole_numbers (10, 10);
cout << whole_numbers[11];
return 0;
}
Output: 0
Conclusion: The vector element access using subscript notation doesn’t provide bounds checking.
Using at()
method
The vector library provides at()
method for vector objects to fetch/modify the values in the vector object. The syntax for the same is as follows:
vector_var.at(index);
This behaves in a similar way as that of the subscript access but at()
method provides bounds checking. That is, the value of the index should be strictly between 0 and size - 1
. Else, the method throws an exception.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector <int> whole_numbers (10, 10);
cout << whole_numbers.at(11);
return 0;
}
Output:
Error:
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 11) >= this->size() (which is 10)
Conclusion: at()
method provides bound checking.
Methods of vector class
C++ provides a rich library of methods to use with vectors. They are listed and described in the below table. For an example, consider a vector named num.
Method | Description | Return type | Parameters |
size | Return size of the vector | size_t | None |
max_size | Return the maximum size which the vector is capable of holding | size_t | None |
resize | Change size | void | (int new_size, int initialisation_value) initialisation_value is optional and by default is 0 |
capacity | Return size of allocated storage capacity | size_t | None |
empty | Test whether the vector is empty | boolean | None |
reserve | Requests that the vector capacity is at least enough to contain ‘n’ elements. | void | n |
shrink_to_fit | Requests the container to reduce its capacity to fit its size. | void | None |
at | Access element at the specified index | The data type of the vector elements | Index value between 0 and size – 1 inclusive |
front | Access first element | The data type of the vector elements | None |
back | Access last element | The data type of the vector elements | None |
data | Returns a direct pointer to the memory array used internally by the vector to store its owned elements. | Pointer to vector element data type | None |
assign | Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. | void | size_t n: the new size of the vector value: to fill the vector with |
push_back | Add element at the end | void | Element of same data type as that of the vector |
pop_back | Delete the last element | void | None |
insert | Insert elements | An iterator that points to the first of the newly inserted elements. | Iterator position and value to be inserted |
erase | Removes from the vector either a single element (position) or a range of elements ([first_iterator, last_iterator)) | An iterator pointing to the new location of the element that followed the last element erased by the function call. | Iterator to the element to be deleted or 2 iterators: one to the beginning and the other to the end |
swap | Exchanges the content of the container by the content of x, which is another vector object of the same type. Sizes may differ. | void | Reference to another vector x |
clear | Removes all elements from the vector (which are destroyed), leaving the container with a size of 0. | void | none |
emplace | Construct and insert element | Iterator to the new element inserted | Iterator position to insert the new value and the new value |
emplace_back | Construct and insert an element at the end | void | The new value to insert |
2D Vectors
It is possible to create multi-dimensional vectors in C++. The syntax of the declaration of a 2D vector is as follows:
vector <vector <data_type>> vector_var;
Exercises
- Eleven integer values are entered from the keyboard. The first 10 are to be stored in a vector. Search for the 11th integer in the vector. Write a program to display the number of times it appears in the vector.
- Read the size of the vector and declare the vector with the size entered. Read the vector elements and also read a key value. Display the number of times the key has appeared in the vector.
- Implement the Selection Sort, Bubble Sort and Insertion sort algorithms on a set of 10 numbers using vectors.
- Read the size of the vector and declare the vector with the size entered. Read the vector elements and sort the array using selection sort, bubble sort and insertion sort.
- Implement the Sieve of Eratosthenes and print the first 100 prime numbers. The algorithm is as follows:
- Fill vector values[100] with numbers from 1 to 100.
- Starting with the second entry in the array, set all its multiples to zero.
- Proceed to the next non-zero element and set all its multiples to zero.
- Repeat step 3 till you have set up the multiples of all the non-zero elements to zero.
- After step 4, all the non-zero entries left in the array would be prime numbers, so print out these numbers.
- Write a program to copy the contents of one vector into another in reverse order.
- Write a program to check if a vector is symmetric. That is, in a vector array_id check if array_id[0] = array_id[n-1], array_id[1] = array_id[n-2] and so on, where n is the size of the vector. Statically initialize the array or take user input.
- Find the smallest number, the largest number, and an average of values in a vector of floating-point numbers.
- Write a function to find the norm of a matrix. The norm is defined as the square root of the sum of squares of all elements in the matrix.
- Write a program to read 10 coordinates. Each coordinate contains 2 floating-point values X and Y. Print the two farthest points and 2 nearest points in the vector.