std::vector
#include <vector>
template <class T, class Alloc = allocator<T>> class vector;
std::vector trong C++ là một container tuần tự (sequence container) biểu diễn một mảng động (dynamic array). Nó cung cấp khả năng lưu trữ các phần tử liên tục trong bộ nhớ, cho phép truy cập ngẫu nhiên nhanh chóng và tự động điều chỉnh kích thước khi cần thiết.
Tham số
T
- Kiểu dữ liệu của các phần tử trong vector.
Alloc
- Kiểu cấp phát bộ nhớ, mặc định là
std::allocator<T>
. Thường bạn không cần quan tâm đến tham số này.
vector
- Tên của vector bạn muốn tạo.
Đặc điểm
- Kích thước động: vector tự động thay đổi kích thước khi thêm hoặc xóa phần tử.
- Quản lý bộ nhớ tự động: vector tự động quản lý cấp phát và giải phóng bộ nhớ khi kích thước thay đổi.
- Truy cập ngẫu nhiên: Cho phép truy cập trực tiếp đến bất kỳ phần tử nào qua chỉ số (giống mảng).
- Tích hợp với iterator: vector cung cấp các iterator để duyệt và thao tác với các phần tử trong container này.
- Lưu trữ liên tục: Các phần tử trong vector được lưu trữ liên tục trong bộ nhớ.
- Chèn/xóa ở cuối hiệu quả: Việc chèn và xóa phần tử ở cuối vector (
push_back()
,pop_back()
) có độ phức tạp trung bình làO(1)
(amortized). - Chèn/xóa ở giữa hoặc đầu kém hiệu quả: Việc chèn hoặc xóa phần tử ở giữa hoặc đầu vector có độ phức tạp tuyến tính
O(n)
do phải di chuyển các phần tử phía sau. - Có thể làm thay đổi iterator: Các thao tác chèn hoặc xóa phần tử trong vector có thể làm thay đổi (invalidate) các iterator đang trỏ đến các phần tử khác trong vector.
- Khi nào nên sử dụng vector:
- Khi bạn cần lưu trữ một tập hợp các phần tử cùng kiểu.
- Khi bạn cần truy cập ngẫu nhiên các phần tử thường xuyên.
- Khi bạn chủ yếu thêm phần tử vào cuối vector.
- Khi bạn biết trước số lượng phần tử tối đa hoặc có thể ước lượng được,
reserve()
có thể được sử dụng để tối ưu hiệu suất.
Ví dụ:
#include <iostream>
#include <vector>
int main() {
// Khởi tạo một vector kiểu int
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Thêm phần tử vào vector
numbers.push_back(6);
// Truy cập và in các phần tử
for (int num : numbers) {
std::cout << num << " ";
}
return 0;
}
Các cách phổ biến khai báo và khởi tạo một vector
-
Khai báo một vector trống:
// Khởi tạo một vector trống, không chứa phần tử nào.
std::vector<int> v1; -
Khai báo và khởi tạo với kích thước cố định:
// Khởi tạo một vector với 10 phần tử mặc định
// (giá trị mặc định của int là 0).
std::vector<int> v2(10); -
Khai báo và khởi tạo với kích thước cố định và giá trị khởi tạo:
// Khởi tạo một vector với 10 phần tử, mỗi phần tử có giá trị là 5.
std::vector<int> v3(10, 5); -
Khởi tạo từ một mảng C++:
int arr[] = {1, 2, 3, 4, 5};
std::vector<int> v4(arr, arr + sizeof(arr) / sizeof(arr[0])); -
Khởi tạo từ danh sách khởi tạo (initializer list):
std::vector<int> v5 = {1, 2, 3, 4, 5};
// std::vector<int> v5{1, 2, 3, 4, 5}; -
Sao chép từ một vector khác:
// Khởi tạo một vector mới sao chép từ một vector khác.
std::vector<int> v6(v5); -
Khởi tạo từ một phạm vi (range) của iterator:
// Khởi tạo một vector mới từ phạm vi các phần tử của một vector khác.
std::vector<int> v7(v5.begin(), v5.end()); -
Di chuyển từ một vector khác (move semantics):
// Khởi tạo một vector bằng cách di chuyển tài nguyên từ một vector khác,
// v5 sẽ trở thành trống sau khi di chuyển.
std::vector<int> v8(std::move(v5)); -
Khởi tạo sử dụng hàm
std::fill
:std::vector<int> v9(5);
std::fill(v9.begin(), v9.end(), 11);
// {11, 11, 11, 11, 11} -
Khởi tạo sử dụng hàm
std::iota
:// Khởi tạo một vector với các giá trị liên tiếp bắt đầu từ giá trị đã cho
std::vector<int> v10(5);
std::iota(v10.begin(), v10.end(), 11);
// {11, 12, 13, 14, 15} -
Khởi tạo mảng vector 2 chiều sử dụng Constructor với giá trị mặc định:
int rows = 3;
int cols = 4;
int default_value = 1;
// Khởi tạo mảng 2 chiều với giá trị mặc định
std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols, default_value)); -
Khởi tạo mảng vector 2 chiều sử dụng hàm
resize()
:int rows = 3;
int cols = 4;
int default_value = 1;
// Khởi tạo mảng 2 chiều và thay đổi kích thước
std::vector<std::vector<int>> matrix(rows);
for (int i = 0; i < rows; ++i) {
matrix[i].resize(cols, default_value);
} -
Khởi tạo mảng vector 2 chiều sử dụng danh sách khởi tạo (initializer list):
// Khởi tạo mảng 2 chiều với danh sách khởi tạo
std::vector<std::vector<int>> matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
Các kiểu dữ liệu đặc biệt của vector
lưu ý
std::vector
có thể chứa bất kỳ kiểu dữ liệu nào mà bạn có thể định nghĩa hoặc sử dụng trong C++.
Ngoài các kiểu dữ liệu cơ bản như int
, double
, char
và std::string
, một std::vector
trong C++ có thể chứa các kiểu dữ liệu đặc biệt sau:
-
Structs (Cấu trúc):
std::vector
có thể lưu trữ cácstruct
tùy chỉnh do người dùng định nghĩa.struct Student {
std::string name;
int age;
};
std::vector<Student> students; -
Classes (Lớp):
std::vector
cũng có thể lưu trữ các đối tượng của lớp (class). Điều này giúp tổ chức các thành phần của một đối tượng với nhiều phương thức và dữ liệu liên quan.class Book {
public:
std::string title;
std::string author;
};
std::vector<Book> library; -
Con trỏ (Pointers):
std::vector
có thể chứa con trỏ đến các kiểu dữ liệu, như con trỏ tớiint
,double
, hoặc con trỏ tới các đối tượng. Điều này có thể hữu ích khi bạn cần quản lý bộ nhớ động hoặc khi lưu trữ các đối tượng có tính đa hình.std::vector<int*> intPointers;
-
Smart Pointers (Con trỏ thông minh):
Để dễ quản lý và tránh lỗi bộ nhớ, bạn có thể sử dụng.std::shared_ptr
,std::unique_ptr
, hoặcstd::weak_ptr
làm kiểu dữ liệu chostd::vector
. Con trỏ thông minh giúp quản lý tự động bộ nhớ cấp phát động.#include <memory>
std::vector<std::shared_ptr<Student>> studentPointers; -
Containers lồng nhau (Nested Containers):
std::vector
có thể chứa các containers khác nhưstd::vector
,std::list
,std::deque
,... Ví dụ, một ma trận có thể được biểu diễn bằngstd::vector<std::vector<int>>
.std::vector<std::vector<int>> matrix;
-
Enums (Kiểu liệt kê):
std::vector
cũng có thể chứa các phần tử kiểuenum
, đặc biệt khi bạn cần làm việc với các giá trị cố định định sẵn.enum Color { Red, Green, Blue };
std::vector<Color> colors; -
Tuples:
std::vector
có thể chứastd::tuple
, giúp lưu trữ các nhóm giá trị với kiểu dữ liệu khác nhau mà không cần tạo.struct
.#include <tuple>
std::vector<std::tuple<int, std::string, double>> records; -
Pairs:
std::vector
có thể chứastd::pair
, một cấu trúc chứa cặp giá trị, hữu ích cho các cấu trúc dữ liệu như danh sách khóa-giá trị.#include <utility>
std::vector<std::pair<int, std::string>> id_name_pairs;
Các hàm thành viên
= | Gán nội dung |
Trình lặp (Iterators)
begin | Trả về một iterator trỏ đến phần tử đầu tiên của vector |
end | Trả về một iterator trỏ đến vị trí ngay sau phần tử cuối cùng của vector |
rbegin | Trả về một iterator ngược (reverse iterator) trỏ tới phần tử cuối cùng của vector |
rend | Trả về một iterator ngược trỏ tới phần tử trước phần tử đầu tiên của vector |
cbegin | Trả về một iterator hằng (constant iterator) trỏ tới phần tử đầu tiên của vector |
cend | Trả về một iterator hằng trỏ tới phần tử ngay sau phần tử cuối cùng của vector |
crbegin | Trả về một iterator ngược hằng (constant reverse iterator) trỏ tới phần tử cuối cùng của vector |
crend | Trả về một iterator ngược hằng trỏ tới phần tử trước phần tử đầu tiên của vector |
Dung lượng (Capacity)
size | Trả về số lượng phần tử hiện có trong vector |
max_size | Trả về số lượng phần tử tối đa mà vector có thể chứa |
resize | Thay đổi kích thước vector |
capacity | Trả về dung lượng hiện tại của vector |
empty | Trả về true nếu vector rỗng, ngược lại trả về false |
reserve | Yêu cầu thay đổi/khởi tạo (trước) dung lượng của vector |
shrink_to_fit | Yêu cầu giảm dung lượng của vector về đúng với kích thước hiện tại, giải phóng bộ nhớ không sử dụng |
Truy cập phần tử
[] | Truy xuất phần tử tại vị trí chỉ định |
at | Truy xuất phần tử tại vị trí chỉ định |
front | Truy xuất phần tử tại vị trí đầu tiên |
back | Truy xuất phần tử tại vị trí cuối cùng |
data | Trả về con trỏ trỏ tới phần tử đầu tiên của vùng lưu trữ bên trong vector |
Thay đổi nội dung (Modifiers)
assign | Gán giá trị mới cho các phần tử trong vector |
push_back | Thêm một phần tử vào cuối vector |
pop_back | Xóa phần tử cuối cùng của vector |
insert | Chèn một hoặc nhiều phần tử vào vị trí chỉ định trong vector |
erase | Xóa một hoặc nhiều phần tử khỏi vector |
swap | Hoán đổi nội dung của hai vector |
clear | Xóa tất cả các phần tử trong vector |
emplace | Chèn một phần tử mới vào vị trí xác định trong vector, xây dựng phần tử tại chỗ |
emplace_back | Thêm một phần tử mới vào cuối vector, xây dựng phần tử tại chỗ |
Cấp phát (Allocator)
get_allocator | Trả về đối tượng bộ cấp phát (allocator) mà vector đang sử dụng để quản lý bộ nhớ |
Toán tử quan hệ | Các toán tử quan hệ trong vector |