Skip to content

Vector - Container động linh hoạt

📖 Giới thiệu

Vector là container động trong STL, tương tự như mảng nhưng có thể thay đổi kích thước tự động. Vector lưu trữ các phần tử liên tiếp trong bộ nhớ và cung cấp truy cập ngẫu nhiên nhanh chóng.

Ví dụ đơn giản đầu tiên

cpp
#include <iostream>
#include <vector>
using namespace std;

int main() {
    // Tạo vector rỗng
    vector<int> numbers;
    
    // Thêm phần tử
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);
    
    // Hiển thị
    cout << "Vector có " << numbers.size() << " phần tử: ";
    for (int num : numbers) {
        cout << num << " ";
    }
    cout << endl;
    
    // Truy cập phần tử
    cout << "Phần tử đầu: " << numbers[0] << endl;
    cout << "Phần tử cuối: " << numbers.back() << endl;
    
    return 0;
}

🔧 Cú pháp

Khai báo Vector

cpp
#include <vector>

vector<int> int_vector;                    // Vector rỗng
vector<int> sized_vector(5);              // 5 phần tử mặc định (0)
vector<int> init_vector(5, 10);           // 5 phần tử, giá trị 10
vector<int> copy_vector{1, 2, 3, 4, 5};   // Khởi tạo với list
vector<int> from_array(arr, arr + size);  // Từ mảng

Các phương thức cơ bản

cpp
// Thêm/xóa phần tử
vector.push_back(value);        // Thêm cuối
vector.pop_back();              // Xóa cuối
vector.insert(iterator, value); // Chèn tại vị trí
vector.erase(iterator);         // Xóa tại vị trí

// Truy cập
vector[index];                  // Truy cập trực tiếp
vector.at(index);              // Truy cập an toàn
vector.front();                // Phần tử đầu
vector.back();                 // Phần tử cuối

// Thông tin
vector.size();                 // Số phần tử
vector.capacity();             // Dung lượng hiện tại
vector.empty();                // Kiểm tra rỗng
vector.clear();                // Xóa tất cả

🔬 Phân tích & Giải thích

Vector vs Array

Vector:

  • Kích thước động
  • Tự động quản lý bộ nhớ
  • Nhiều phương thức hữu ích
  • Overhead nhỏ

Array:

  • Kích thước cố định
  • Quản lý bộ nhớ thủ công
  • Ít tính năng
  • Hiệu suất cao hơn một chút

Memory Management trong Vector

cpp
vector<int> v;
cout << "Capacity: " << v.capacity() << ", Size: " << v.size() << endl;

for (int i = 0; i < 10; i++) {
    v.push_back(i);
    cout << "After push " << i << " - Capacity: " << v.capacity() 
         << ", Size: " << v.size() << endl;
}

💻 Ví dụ minh họa

Ví dụ 1: Quản lý danh sách sinh viên

cpp
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iomanip>
using namespace std;

struct SinhVien {
    string ten;
    int tuoi;
    double diem;
    
    SinhVien(string t, int tuoi_sv, double d) : ten(t), tuoi(tuoi_sv), diem(d) {}
    
    void hien_thi() const {
        cout << setw(15) << ten << setw(5) << tuoi << setw(8) << fixed << setprecision(1) << diem << endl;
    }
};

class QuanLySinhVien {
private:
    vector<SinhVien> danh_sach;
    
public:
    void them_sinh_vien(const string& ten, int tuoi, double diem) {
        danh_sach.emplace_back(ten, tuoi, diem);
        cout << "✅ Đã thêm sinh viên: " << ten << endl;
    }
    
    void xoa_sinh_vien(const string& ten) {
        auto it = find_if(danh_sach.begin(), danh_sach.end(),
                         [&ten](const SinhVien& sv) { return sv.ten == ten; });
        
        if (it != danh_sach.end()) {
            danh_sach.erase(it);
            cout << "✅ Đã xóa sinh viên: " << ten << endl;
        } else {
            cout << "❌ Không tìm thấy sinh viên: " << ten << endl;
        }
    }
    
    void tim_sinh_vien(const string& ten) {
        auto it = find_if(danh_sach.begin(), danh_sach.end(),
                         [&ten](const SinhVien& sv) { return sv.ten == ten; });
        
        if (it != danh_sach.end()) {
            cout << "🔍 Tìm thấy sinh viên:" << endl;
            cout << setw(15) << "Tên" << setw(5) << "Tuổi" << setw(8) << "Điểm" << endl;
            cout << string(28, '-') << endl;
            it->hien_thi();
        } else {
            cout << "❌ Không tìm thấy sinh viên: " << ten << endl;
        }
    }
    
    void hien_thi_tat_ca() {
        if (danh_sach.empty()) {
            cout << "📋 Danh sách sinh viên trống!" << endl;
            return;
        }
        
        cout << "\n📋 DANH SÁCH SINH VIÊN (" << danh_sach.size() << " sinh viên)" << endl;
        cout << setw(15) << "Tên" << setw(5) << "Tuổi" << setw(8) << "Điểm" << endl;
        cout << string(28, '-') << endl;
        
        for (const auto& sv : danh_sach) {
            sv.hien_thi();
        }
        cout << string(28, '-') << endl;
    }
    
    void sap_xep_theo_diem() {
        sort(danh_sach.begin(), danh_sach.end(),
             [](const SinhVien& a, const SinhVien& b) {
                 return a.diem > b.diem;  // Giảm dần
             });
        cout << "✅ Đã sắp xếp theo điểm (cao → thấp)" << endl;
    }
    
    void sap_xep_theo_ten() {
        sort(danh_sach.begin(), danh_sach.end(),
             [](const SinhVien& a, const SinhVien& b) {
                 return a.ten < b.ten;  // A → Z
             });
        cout << "✅ Đã sắp xếp theo tên (A → Z)" << endl;
    }
    
    void thong_ke() {
        if (danh_sach.empty()) {
            cout << "📊 Không có dữ liệu để thống kê!" << endl;
            return;
        }
        
        double tong_diem = 0;
        double diem_cao_nhat = danh_sach[0].diem;
        double diem_thap_nhat = danh_sach[0].diem;
        int so_sv_gioi = 0, so_sv_kha = 0, so_sv_tb = 0, so_sv_yeu = 0;
        
        for (const auto& sv : danh_sach) {
            tong_diem += sv.diem;
            diem_cao_nhat = max(diem_cao_nhat, sv.diem);
            diem_thap_nhat = min(diem_thap_nhat, sv.diem);
            
            if (sv.diem >= 8.0) so_sv_gioi++;
            else if (sv.diem >= 6.5) so_sv_kha++;
            else if (sv.diem >= 5.0) so_sv_tb++;
            else so_sv_yeu++;
        }
        
        cout << "\n📊 THỐNG KÊ" << endl;
        cout << "Tổng số sinh viên: " << danh_sach.size() << endl;
        cout << "Điểm trung bình: " << fixed << setprecision(2) << (tong_diem / danh_sach.size()) << endl;
        cout << "Điểm cao nhất: " << diem_cao_nhat << endl;
        cout << "Điểm thấp nhất: " << diem_thap_nhat << endl;
        cout << "Phân loại:" << endl;
        cout << "  - Giỏi (≥8.0): " << so_sv_gioi << " sinh viên" << endl;
        cout << "  - Khá (6.5-7.9): " << so_sv_kha << " sinh viên" << endl;
        cout << "  - Trung bình (5.0-6.4): " << so_sv_tb << " sinh viên" << endl;
        cout << "  - Yếu (<5.0): " << so_sv_yeu << " sinh viên" << endl;
    }
    
    vector<SinhVien> loc_theo_diem(double diem_toi_thieu) {
        vector<SinhVien> ket_qua;
        
        copy_if(danh_sach.begin(), danh_sach.end(), back_inserter(ket_qua),
                [diem_toi_thieu](const SinhVien& sv) {
                    return sv.diem >= diem_toi_thieu;
                });
        
        cout << "🔍 Tìm thấy " << ket_qua.size() << " sinh viên có điểm ≥ " << diem_toi_thieu << endl;
        return ket_qua;
    }
    
    size_t kich_thuoc() const {
        return danh_sach.size();
    }
};

int main() {
    cout << "=== HỆ THỐNG QUẢN LÝ SINH VIÊN ===" << endl;
    
    QuanLySinhVien ql;
    
    // Thêm sinh viên
    cout << "\n--- Thêm sinh viên ---" << endl;
    ql.them_sinh_vien("Nguyễn Văn A", 20, 8.5);
    ql.them_sinh_vien("Trần Thị B", 19, 7.2);
    ql.them_sinh_vien("Lê Văn C", 21, 9.1);
    ql.them_sinh_vien("Phạm Thị D", 20, 6.8);
    ql.them_sinh_vien("Hoàng Văn E", 22, 4.5);
    
    // Hiển thị danh sách
    ql.hien_thi_tat_ca();
    
    // Thống kê
    ql.thong_ke();
    
    // Sắp xếp theo điểm
    cout << "\n--- Sắp xếp theo điểm ---" << endl;
    ql.sap_xep_theo_diem();
    ql.hien_thi_tat_ca();
    
    // Sắp xếp theo tên
    cout << "\n--- Sắp xếp theo tên ---" << endl;
    ql.sap_xep_theo_ten();
    ql.hien_thi_tat_ca();
    
    // Tìm kiếm
    cout << "\n--- Tìm kiếm ---" << endl;
    ql.tim_sinh_vien("Lê Văn C");
    ql.tim_sinh_vien("Nguyễn Văn X");
    
    // Lọc sinh viên giỏi
    cout << "\n--- Lọc sinh viên giỏi ---" << endl;
    auto sv_gioi = ql.loc_theo_diem(8.0);
    if (!sv_gioi.empty()) {
        cout << "Danh sách sinh viên giỏi:" << endl;
        cout << setw(15) << "Tên" << setw(5) << "Tuổi" << setw(8) << "Điểm" << endl;
        cout << string(28, '-') << endl;
        for (const auto& sv : sv_gioi) {
            sv.hien_thi();
        }
    }
    
    // Xóa sinh viên
    cout << "\n--- Xóa sinh viên ---" << endl;
    ql.xoa_sinh_vien("Hoàng Văn E");
    ql.hien_thi_tat_ca();
    
    return 0;
}

Ví dụ 2: Vector 2D và ma trận

cpp
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;

class Matrix {
private:
    vector<vector<int>> data;
    int rows, cols;
    
public:
    Matrix(int r, int c) : rows(r), cols(c) {
        data.resize(rows, vector<int>(cols, 0));
        cout << "Tạo ma trận " << rows << "x" << cols << endl;
    }
    
    Matrix(const vector<vector<int>>& init_data) {
        data = init_data;
        rows = data.size();
        cols = rows > 0 ? data[0].size() : 0;
        cout << "Tạo ma trận từ dữ liệu sẵn có " << rows << "x" << cols << endl;
    }
    
    void nhap_du_lieu() {
        cout << "Nhập dữ liệu cho ma trận " << rows << "x" << cols << ":" << endl;
        for (int i = 0; i < rows; i++) {
            cout << "Dòng " << (i + 1) << ": ";
            for (int j = 0; j < cols; j++) {
                cin >> data[i][j];
            }
        }
    }
    
    void nhap_ngau_nhien(int min_val = 1, int max_val = 10) {
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                data[i][j] = min_val + rand() % (max_val - min_val + 1);
            }
        }
        cout << "Đã điền ma trận với số ngẫu nhiên (" << min_val << "-" << max_val << ")" << endl;
    }
    
    void hien_thi() const {
        cout << "\nMa trận " << rows << "x" << cols << ":" << endl;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                cout << setw(4) << data[i][j];
            }
            cout << endl;
        }
        cout << endl;
    }
    
    Matrix cong(const Matrix& other) const {
        if (rows != other.rows || cols != other.cols) {
            throw invalid_argument("Kích thước ma trận không khớp để cộng!");
        }
        
        Matrix result(rows, cols);
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                result.data[i][j] = data[i][j] + other.data[i][j];
            }
        }
        cout << "Đã thực hiện phép cộng ma trận" << endl;
        return result;
    }
    
    Matrix nhan(const Matrix& other) const {
        if (cols != other.rows) {
            throw invalid_argument("Không thể nhân ma trận: số cột của ma trận 1 ≠ số dòng của ma trận 2!");
        }
        
        Matrix result(rows, other.cols);
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < other.cols; j++) {
                for (int k = 0; k < cols; k++) {
                    result.data[i][j] += data[i][k] * other.data[k][j];
                }
            }
        }
        cout << "Đã thực hiện phép nhân ma trận" << endl;
        return result;
    }
    
    Matrix chuyen_vi() const {
        Matrix result(cols, rows);
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                result.data[j][i] = data[i][j];
            }
        }
        cout << "Đã thực hiện chuyển vị ma trận" << endl;
        return result;
    }
    
    void nhan_voi_so(int scalar) {
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                data[i][j] *= scalar;
            }
        }
        cout << "Đã nhân ma trận với số " << scalar << endl;
    }
    
    vector<int> tim_max_moi_dong() const {
        vector<int> max_values;
        for (int i = 0; i < rows; i++) {
            int max_val = data[i][0];
            for (int j = 1; j < cols; j++) {
                max_val = max(max_val, data[i][j]);
            }
            max_values.push_back(max_val);
        }
        return max_values;
    }
    
    vector<int> tim_min_moi_cot() const {
        vector<int> min_values;
        for (int j = 0; j < cols; j++) {
            int min_val = data[0][j];
            for (int i = 1; i < rows; i++) {
                min_val = min(min_val, data[i][j]);
            }
            min_values.push_back(min_val);
        }
        return min_values;
    }
    
    int tinh_tong() const {
        int sum = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                sum += data[i][j];
            }
        }
        return sum;
    }
    
    double tinh_trung_binh() const {
        return static_cast<double>(tinh_tong()) / (rows * cols);
    }
    
    int get_rows() const { return rows; }
    int get_cols() const { return cols; }
};

void demo_matrix_operations() {
    cout << "=== DEMO OPERATIONS VỚI MA TRẬN ===" << endl;
    
    srand(time(0));  // Seed for random numbers
    
    // Tạo ma trận
    cout << "\n--- Tạo ma trận ---" << endl;
    Matrix ma_tran_A(3, 3);
    Matrix ma_tran_B(3, 3);
    
    ma_tran_A.nhap_ngau_nhien(1, 5);
    ma_tran_B.nhap_ngau_nhien(1, 5);
    
    cout << "Ma trận A:";
    ma_tran_A.hien_thi();
    
    cout << "Ma trận B:";
    ma_tran_B.hien_thi();
    
    // Phép cộng
    cout << "\n--- Phép cộng A + B ---" << endl;
    try {
        Matrix tong = ma_tran_A.cong(ma_tran_B);
        cout << "Kết quả A + B:";
        tong.hien_thi();
    } catch (const exception& e) {
        cout << "Lỗi: " << e.what() << endl;
    }
    
    // Phép nhân
    cout << "\n--- Phép nhân A × B ---" << endl;
    try {
        Matrix tich = ma_tran_A.nhan(ma_tran_B);
        cout << "Kết quả A × B:";
        tich.hien_thi();
    } catch (const exception& e) {
        cout << "Lỗi: " << e.what() << endl;
    }
    
    // Chuyển vị
    cout << "\n--- Chuyển vị ma trận A ---" << endl;
    Matrix chuyen_vi_A = ma_tran_A.chuyen_vi();
    cout << "Chuyển vị của A:";
    chuyen_vi_A.hien_thi();
    
    // Nhân với scalar
    cout << "\n--- Nhân A với số 3 ---" << endl;
    Matrix ma_tran_A_copy = ma_tran_A;  // Copy for demo
    ma_tran_A_copy.nhan_voi_so(3);
    cout << "A × 3:";
    ma_tran_A_copy.hien_thi();
    
    // Phân tích ma trận
    cout << "\n--- Phân tích ma trận A ---" << endl;
    vector<int> max_dong = ma_tran_A.tim_max_moi_dong();
    vector<int> min_cot = ma_tran_A.tim_min_moi_cot();
    
    cout << "Max mỗi dòng: ";
    for (int i = 0; i < max_dong.size(); i++) {
        cout << "Dòng " << (i+1) << ": " << max_dong[i] << "  ";
    }
    cout << endl;
    
    cout << "Min mỗi cột: ";
    for (int j = 0; j < min_cot.size(); j++) {
        cout << "Cột " << (j+1) << ": " << min_cot[j] << "  ";
    }
    cout << endl;
    
    cout << "Tổng tất cả phần tử: " << ma_tran_A.tinh_tong() << endl;
    cout << "Giá trị trung bình: " << fixed << setprecision(2) << ma_tran_A.tinh_trung_binh() << endl;
}

int main() {
    demo_matrix_operations();
    return 0;
}

🏋️ Thực hành

Bài tập 1: Quản lý kho hàng

Tạo class KhoHang sử dụng vector<SanPham> với:

  • Thêm, xóa, sửa sản phẩm
  • Tìm kiếm theo tên, loại
  • Sắp xếp theo giá, số lượng

Bài tập 2: Vector calculator

Tạo class VectorCalculator với:

  • Các phép toán vector: cộng, trừ, nhân scalar
  • Tích vô hướng, độ dài vector
  • Góc giữa hai vector

Bài tập 3: Game inventory

Tạo hệ thống inventory cho game với:

  • vector<Item> lưu đồ vật
  • Sorting theo giá trị, rarity
  • Filtering theo loại item

📋 Tóm tắt

  1. Vector: Container động, tự động thay đổi kích thước

  2. Ưu điểm:

    • Truy cập ngẫu nhiên O(1)
    • Thêm/xóa cuối O(1) amortized
    • Cache-friendly (phần tử liên tiếp)
    • Nhiều algoritm STL hỗ trợ
  3. Nhược điểm:

    • Chèn/xóa giữa O(n)
    • Có thể reallocate khi hết capacity
  4. Khi nào dùng:

    • Cần truy cập ngẫu nhiên
    • Thường thêm/xóa ở cuối
    • Cần tương thích với C arrays

Bài tiếp theo: List - Tìm hiểu về linked list và insertion/deletion hiệu quả.

Khóa học C++ miễn phí