Sequence Containers
vector
std::vector là cấu trúc dữ liệu mảng liền kề trong bộ nhớ, độ dài biến đổi (còn gọi là danh sách) do STL cung cấp. Cho phép chèn/xóa tuyến tính và truy cập ngẫu nhiên hằng số.
Vì sao dùng vector
Là OIer, theo đuổi hiệu năng thường cao hơn ổn định ở mức工程. vector do xử lý bộ nhớ động nên trong một số trường hợp chậm hơn mảng tĩnh, và trên OJ không bật tối ưu có thể còn tệ hơn. Vì vậy khi lưu dữ liệu bình thường thường không chọn vector. Dưới đây là các đặc tính nổi bật giúp vector hữu ích khi cần.
vector có thể cấp phát động
Nhiều lúc không thể cấp sẵn đủ lớn (vd: tiền xử lý ước của 1~n). Dù biết tổng dữ liệu đủ nhỏ, nhưng từng phần có thể rất lớn, khi đó cần vector để kiểm soát bộ nhớ. vector cũng hỗ trợ mở rộng động, rất hữu ích khi bộ nhớ hạn chế.
vector nạp chồng toán tử so sánh và gán
vector nạp chồng 6 toán tử so sánh theo thứ tự từ điển, giúp so sánh hai container thuận tiện (độ phức tạp tuyến tính theo kích thước). Ví dụ có thể dùng vector<char> so sánh chuỗi (nhưng std::string vẫn nhanh và tiện hơn). Ngoài ra vector nạp chồng toán tử gán, giúp sao chép mảng dễ dàng.
vector khởi tạo tiện lợi
Vì vector nạp chồng =, ta có thể gán cả vector. Từ C++11, vector hỗ trợ list initialization, ví dụ vector<int> data {1, 2, 3};.
Cách dùng vector
Giới thiệu thao tác thường dùng, chi tiết xem tài liệu C++.
Hàm dựng
Ví dụ (giả sử đã using các loại trong std):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Mã test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Có thể dùng các cách trên để dựng vector, đủ cho hầu hết trường hợp.
Truy cập phần tử
vector cung cấp các cách truy cập sau:
-
at()v.at(pos)trả về tham chiếu phần tử ở vị trípos. Nếu vượt biên némstd::out_of_range. -
operator[]v[pos]trả về tham chiếu phần tử ởpos. Không kiểm tra biên. -
front()v.front()trả về tham chiếu phần tử đầu. -
back()v.back()trả về tham chiếu phần tử cuối. -
data()v.data()trả về con trỏ tới phần tử đầu trong vùng nhớ liên tiếp củav.
Iterator
vector cung cấp các iterator sau:
-
begin()/cbegin()Trả về iterator trỏ đến phần tử đầu,
*begin = front. -
end()/cend()Trả về iterator trỏ đến vị trí sau phần tử cuối, không có phần tử.
-
rbegin()/crbegin()Trả về reverse iterator trỏ đến phần tử đầu của dãy đảo, có thể hiểu là phần tử cuối của container thường.
-
rend()/crend()Trả về reverse iterator trỏ đến vị trí sau phần tử cuối của dãy đảo (trước phần tử đầu).
Iterator có c là chỉ đọc; không thể sửa phần tử qua iterator đó. Nếu vector là hằng thì iterator thường và chỉ đọc tương đương. Iterator chỉ đọc hỗ trợ từ C++11.
Độ dài và dung lượng
vector có các hàm liên quan đến độ dài và dung lượng. Lưu ý: độ dài (size) là số phần tử hiệu lực, dung lượng (capacity) là lượng bộ nhớ đã cấp. Chi tiết xem phần triển khai.
Liên quan đến độ dài:
-
empty()trả vềbool, tứcv.begin() == v.end();truerỗng,falsekhông rỗng. -
size()trả về độ dài, tứcstd::distance(v.begin(), v.end()). -
resize(n)đổi độ dài thànhn. Nếunlớn hơn, sẽ bổ sung phần tử (dùng giá trị truyền vào nếu có, nếu không dùng mặc định); nếunnhỏ hơn, giữnphần tử đầu và xóa phần còn lại. -
max_size()trả về độ dài tối đa có thể.Liên quan đến dung lượng:
-
reserve()chovectordự trữ bộ nhớ, tránh cấp phát/copy không cần thiết. -
capacity()trả về dung lượng hiện tại. -
shrink_to_fit()đưa dung lượng về đúng độ dài, loại bỏ phần dư.
Thêm/xóa/sửa phần tử
clear()xóa toàn bộ phần tửinsert()chèn tại vị trí iterator, có thể chèn nhiều. Độ phức tạp tuyến tính theo khoảng cách tới cuốierase()xóa phần tử hoặc đoạn, trả về iterator sau phần tử bị xóa cuối cùng. Độ phức tạp nhưinsert.push_back()chèn cuối, độ phức tạp trung bình hằng số, tệ nhất tuyến tính.pop_back()xóa cuối, hằng số.swap()đổi với container khác, hằng số.
Chi tiết triển khai vector
vector thực chất là mảng cố định; mở rộng động nhờ tránh tràn số lượng. vector lưu riêng số phần tử \(n\) và dung lượng \(N\). Khi thêm phần tử mà \(n>N\), container sẽ cấp một mảng kích thước \(2N\), copy dữ liệu sang mảng mới, rồi giải phóng mảng cũ. Dù thao tác này có độ phức tạp \(O(n)\), nhưng có thể chứng minh độ phức tạp trung bình là \(O(1)\). Xóa ở cuối và truy cập vẫn là \(O(1)\).
Do đó, nếu ước lượng tốt kích thước và dùng resize()/reserve() hợp lý, hiệu năng vector sẽ gần như mảng tĩnh.
vector<bool>
Thư viện chuẩn có đặc hóa vector<bool>, mỗi bool chỉ chiếm 1 bit và hỗ trợ tăng động. Nhưng operator[] không trả về bool& mà là vector<bool>::reference. Vì vậy dùng vector<bool> cần cẩn thận; có thể dùng deque<bool> hoặc vector<char> thay thế. Nếu cần tiết kiệm bộ nhớ, hãy dùng bitset.
array(C++11)
std::array là cấu trúc dữ liệu mảng liền kề, độ dài cố định do STL cung cấp. Bản chất là bọc mảng C.
Vì sao dùng array
array là bọc STL cho mảng. So với vector, nó hi sinh mở rộng động để đổi lấy hiệu năng gần như mảng C (khi bật tối ưu). Vì vậy khi có C++11, các nơi dùng mảng tĩnh có thể dùng array; mảng cấp phát động có thể thay bằng vector.
Hàm thành viên
Hàm thành viên được định nghĩa ngầm
| Hàm | Tác dụng |
|---|---|
operator= |
Gán từng phần tử của một array khác vào array hiện tại |
Truy cập phần tử
| Hàm | Tác dụng |
|---|---|
at |
Truy cập phần tử với kiểm tra biên |
operator[] |
Truy cập phần tử, không kiểm tra biên |
front |
Truy cập phần tử đầu |
back |
Truy cập phần tử cuối |
data |
Trả về con trỏ tới phần tử đầu trong bộ nhớ |
at ném std::out_of_range nếu pos >= size().
Dung lượng
| Hàm | Tác dụng |
|---|---|
empty |
Kiểm tra rỗng |
size |
Số phần tử |
max_size |
Số phần tử tối đa |
Vì array là cố định, size() = max_size().
Thao tác
| Hàm | Tác dụng |
|---|---|
fill |
Điền giá trị |
swap |
Hoán đổi |
Lưu ý: hoán đổi hai array là \(\Theta(\text{size})\), không phải \(O(1)\).
Hàm không phải thành viên
| Hàm | Tác dụng |
|---|---|
operator==... |
So sánh theo từ điển |
std::get |
Truy cập phần tử |
std::swap |
Thuật toán std::swap đặc hóa |
Ví dụ array:
1 2 3 4 5 6 7 8 9 | |
deque
std::deque là deque trong STL. Cho phép chèn/xóa tuyến tính, truy cập ngẫu nhiên hằng số.
Cách dùng deque
Giới thiệu cách dùng thường gặp, chi tiết xem tài liệu C++. Các iterator như vector, nên không trình bày lại.
Hàm dựng
Ví dụ (giả sử đã using các loại trong std):
1 2 3 4 5 6 7 8 9 10 11 12 | |
Truy cập phần tử
Giống vector, nhưng không thể truy cập bộ nhớ nền. Tốc độ truy cập tham khảo phần triển khai.
at()trả về tham chiếu phần tử, có kiểm tra biên, hằng số.operator[]trả về tham chiếu phần tử, không kiểm tra biên, hằng số.front()trả về tham chiếu phần tử đầu.back()trả về tham chiếu phần tử cuối.
Iterator
Giống vector.
Độ dài
Giống vector, nhưng không có reserve() và capacity() (vẫn có shrink_to_fit()).
Thêm/xóa/sửa phần tử
Giống vector, và thêm thao tác ở đầu.
clear()xóa toàn bộ phần tửinsert()chèn tại iterator, có thể chèn nhiều. Độ phức tạp tuyến tính theo khoảng cách tới đầu/cuối gần hơn.erase()xóa phần tử hoặc đoạn, trả về iterator sau phần tử bị xóa cuối cùng. Độ phức tạp nhưinsert.push_front()chèn đầu, hằng số.pop_front()xóa đầu, hằng số.push_back()chèn cuối, hằng số.pop_back()xóa cuối, hằng số.swap()đổi với container khác, hằng số.
Chi tiết triển khai deque
deque thường được hiện thực bởi nhiều buffer không liên tiếp, nhưng mỗi buffer là liên tiếp. Mỗi buffer lưu con trỏ đầu/cuối để đánh dấu vùng dữ liệu. Khi buffer đầy sẽ cấp thêm buffer trước hoặc sau để chứa thêm dữ liệu. Xem thêm 《STL 源码剖析》deque 实现原理.
list
std::list là danh sách liên kết đôi. Truy cập ngẫu nhiên tuyến tính, chèn/xóa hằng số.
Cách dùng list
Cách dùng gần giống deque nhưng độ phức tạp khác. Xem tài liệu C++. Các iterator/độ dài/thêm xóa giống deque nên không trình bày lại.
Truy cập phần tử
Vì là danh sách liên kết nên không hỗ trợ truy cập ngẫu nhiên; cần dùng iterator.
front()trả về tham chiếu phần tử đầu.back()trả về tham chiếu phần tử cuối.
Thao tác
list có thêm các thuật toán STL tối ưu cho đặc tính danh sách: splice()、remove()、sort()、unique()、merge().
forward_list(C++11)
std::forward_list là danh sách liên kết đơn, tiết kiệm bộ nhớ hơn std::list.
Cách dùng forward_list
Gần như giống list, nhưng iterator chỉ một chiều nên không trình bày chi tiết. Xem tài liệu C++
Last updated on this page:, Update history
Found an error? Want to help improve? Edit this page on GitHub!
Contributors to this page:MingqiHuang, Xeonacid, greyqz, i-Yirannn, ChenZ01
All content on this page is provided under the terms of the CC BY-SA 4.0 and SATA license, additional terms may apply