Chuyển tới nội dung chính

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

  1. Kích thước động: vector tự động thay đổi kích thước khi thêm hoặc xóa phần tử.
  2. 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.
  3. 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).
  4. 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.
  5. 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ớ.
  6. 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).
  7. 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.
  8. 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.
  9. 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

  1. 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;
  2. 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);
  3. 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);
  4. 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]));
  5. 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};
  6. 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);
  7. 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());
  8. 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));
  9. 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}
  10. 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}
  11. 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));
  12. 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);
    }
  13. 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, charstd::string, một std::vector trong C++ có thể chứa các kiểu dữ liệu đặc biệt sau:

  1. Structs (Cấu trúc):

    std::vector có thể lưu trữ các struct tùy chỉnh do người dùng định nghĩa.
    struct Student {
    std::string name;
    int age;
    };
    std::vector<Student> students;
  2. 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;
  3. Con trỏ (Pointers):

    std::vector có thể chứa con trỏ đến các kiểu dữ liệu, như con trỏ tới int, 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;
  4. 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ặc std::weak_ptr làm kiểu dữ liệu cho std::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;
  5. 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ằng std::vector<std::vector<int>>.
    std::vector<std::vector<int>> matrix;
  6. Enums (Kiểu liệt kê):

    std::vector cũng có thể chứa các phần tử kiểu enum, đặ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;
  7. Tuples:

    std::vector có thể chứa std::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;
  8. Pairs:

    std::vector có thể chứa std::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)

beginTrả về một iterator trỏ đến phần tử đầu tiên của vector
endTrả về một iterator trỏ đến vị trí ngay sau phần tử cuối cùng của vector
rbeginTrả về một iterator ngược (reverse iterator) trỏ tới phần tử cuối cùng của vector
rendTrả về một iterator ngược trỏ tới phần tử trước phần tử đầu tiên của vector
cbeginTrả về một iterator hằng (constant iterator) trỏ tới phần tử đầu tiên của vector
cendTrả về một iterator hằng trỏ tới phần tử ngay sau phần tử cuối cùng của vector
crbeginTrả về một iterator ngược hằng (constant reverse iterator) trỏ tới phần tử cuối cùng của vector
crendTrả 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)

sizeTrả về số lượng phần tử hiện có trong vector
max_sizeTrả về số lượng phần tử tối đa mà vector có thể chứa
resizeThay đổi kích thước vector
capacityTrả về dung lượng hiện tại của vector
emptyTrả về true nếu vector rỗng, ngược lại trả về false
reserveYêu cầu thay đổi/khởi tạo (trước) dung lượng của vector
shrink_to_fitYê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
atTruy xuất phần tử tại vị trí chỉ định
frontTruy xuất phần tử tại vị trí đầu tiên
backTruy xuất phần tử tại vị trí cuối cùng
dataTrả 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)

assignGán giá trị mới cho các phần tử trong vector
push_backThêm một phần tử vào cuối vector
pop_backXóa phần tử cuối cùng của vector
insertChèn một hoặc nhiều phần tử vào vị trí chỉ định trong vector
eraseXóa một hoặc nhiều phần tử khỏi vector
swapHoán đổi nội dung của hai vector
clearXóa tất cả các phần tử trong vector
emplaceChè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_backThê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_allocatorTrả 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