Iterator trong C++
Iterator là một đối tượng dùng để “trỏ” đến một phần tử trong container (vector, map, set…) và di chuyển qua các phần tử khác - hoạt động giống con trỏ, và đây không phải sự trùng hợp: iterator được thiết kế dựa trên khái niệm con trỏ.
Iterator cơ bản với vector
Phần tiêu đề “Iterator cơ bản với vector”#include <vector>#include <iostream>
int main() { std::vector<int> numbers = {10, 20, 30};
std::vector<int>::iterator it = numbers.begin(); // Iterator trỏ đến phần tử đầu tiên
std::cout << *it << std::endl; // 10 - dereference giống con trỏ
++it; // Di chuyển sang phần tử tiếp theo std::cout << *it << std::endl; // 20
return 0;}.begin(): trả về iterator trỏ đến phần tử đầu tiên.end(): trả về iterator trỏ đến vị trí ngay sau phần tử cuối cùng (không phải phần tử cuối!)
Duyệt container bằng iterator
Phần tiêu đề “Duyệt container bằng iterator”#include <vector>#include <iostream>
int main() { std::vector<int> numbers = {10, 20, 30, 40};
for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) { std::cout << *it << " "; } // 10 20 30 40
return 0;}Dùng auto để tránh phải viết kiểu iterator dài dòng:
for (auto it = numbers.begin(); it != numbers.end(); ++it) { std::cout << *it << " ";}Đây thực chất là những gì đang diễn ra “bên dưới” khi bạn dùng range-based for (for (int n : numbers)) - range-based for chỉ là cú pháp gọn hơn của vòng lặp iterator này.
Iterator trên map và set
Phần tiêu đề “Iterator trên map và set”#include <map>#include <iostream>
int main() { std::map<std::string, int> ages = {{"Alice", 25}, {"Bob", 30}};
for (auto it = ages.begin(); it != ages.end(); ++it) { std::cout << it->first << ": " << it->second << std::endl; // -> vì it trỏ đến một pair }
return 0;}Dùng iterator với find(), insert(), erase()
Phần tiêu đề “Dùng iterator với find(), insert(), erase()”Nhiều phương thức của container trả về hoặc yêu cầu iterator làm tham số - đã xuất hiện ở các bài trước mà không giải thích chi tiết:
#include <vector>#include <algorithm>#include <iostream>
int main() { std::vector<int> numbers = {10, 20, 30, 40};
auto it = std::find(numbers.begin(), numbers.end(), 30); // Tìm giá trị 30
if (it != numbers.end()) { std::cout << "Tim thay tai vi tri: " << (it - numbers.begin()) << std::endl; // 2 numbers.erase(it); // Xóa phần tử tại vị trí iterator trỏ đến }
for (int n : numbers) { std::cout << n << " "; } // 10 20 40
return 0;}const_iterator: chỉ đọc, không sửa
Phần tiêu đề “const_iterator: chỉ đọc, không sửa”std::vector<int> numbers = {1, 2, 3};
for (std::vector<int>::const_iterator it = numbers.cbegin(); it != numbers.cend(); ++it) { std::cout << *it << " "; // *it = 100; // LỖI! const_iterator không cho phép sửa đổi}Vì sao iterator quan trọng?
Phần tiêu đề “Vì sao iterator quan trọng?”Iterator cung cấp một giao diện thống nhất để duyệt qua mọi loại container, dù cấu trúc dữ liệu bên dưới hoàn toàn khác nhau (vector liên tục trong bộ nhớ, map là cây nhị phân, set cũng vậy). Nhờ đó, các hàm thuật toán trong <algorithm> (như std::sort, std::find) có thể hoạt động với bất kỳ container nào miễn là nó cung cấp iterator hợp lệ.
Tổng kết
Phần tiêu đề “Tổng kết”- Iterator là đối tượng “trỏ” đến một phần tử trong container, hỗ trợ
*(dereference) và++(di chuyển) giống con trỏ .begin()trỏ đến phần tử đầu tiên;.end()trỏ đến vị trí ngay sau phần tử cuối cùng- Range-based for thực chất là cú pháp gọn hơn của vòng lặp dùng iterator
- Nhiều hàm thuật toán (
std::find,std::sort…) hoạt động thông qua iterator, giúp dùng chung được cho nhiều loại container