Câu trả lời:
Tôi thích it - vec.begin()
chính xác hơn cho lý do ngược lại được đưa ra bởi Naveen: vì vậy nó sẽ không biên dịch nếu bạn thay đổi vectơ thành một danh sách. Nếu bạn làm điều này trong mỗi lần lặp, bạn có thể dễ dàng biến thuật toán O (n) thành thuật toán O (n ^ 2).
Một tùy chọn khác, nếu bạn không nhảy xung quanh trong container trong vòng lặp, sẽ là giữ chỉ mục làm bộ đếm vòng lặp thứ hai.
Lưu ý: it
là tên chung cho trình lặp container , std::container_type::iterator it;
.
it
gì thế
std::container_type::iterator it;
std::list
không cung cấp quyền truy cập trực tiếp vào các yếu tố theo vị trí của chúng, vì vậy nếu bạn không thể làm list[5]
, bạn không nên làm list.begin() + 5
.
Tôi thích std::distance(vec.begin(), it)
vì nó sẽ cho phép tôi thay đổi container mà không có bất kỳ thay đổi mã nào. Ví dụ: nếu bạn quyết định sử dụng std::list
thay vì std::vector
không cung cấp trình lặp truy cập ngẫu nhiên, mã của bạn sẽ vẫn biên dịch. Vì std :: distance chọn phương thức tối ưu tùy thuộc vào các đặc điểm của trình vòng lặp, bạn cũng sẽ không bị suy giảm hiệu năng.
vec
là tin xấu. Nếu mã được viết lại thành chung chung, lấy loại vùng chứa làm tham số mẫu, đó là khi chúng ta có thể (và nên) nói về việc xử lý các trình vòng lặp truy cập không ngẫu nhiên ;-)
vec
là tin xấu, quá.
Như UncleBens và Naveen đã chỉ ra, có những lý do tốt cho cả hai. Cái nào là "tốt hơn" phụ thuộc vào hành vi bạn muốn: Bạn có muốn đảm bảo hành vi không đổi thời gian, hoặc bạn muốn nó quay trở lại thời gian tuyến tính khi cần thiết?
it - vec.begin()
mất thời gian liên tục, nhưng operator -
chỉ được xác định trên các trình vòng lặp truy cập ngẫu nhiên, do đó, mã sẽ không biên dịch được tất cả với các trình vòng lặp danh sách, ví dụ.
std::distance(vec.begin(), it)
hoạt động cho tất cả các loại trình vòng lặp, nhưng sẽ chỉ là một hoạt động thời gian không đổi nếu được sử dụng trên các trình vòng lặp truy cập ngẫu nhiên.
Không ai là "tốt hơn". Sử dụng một trong đó làm những gì bạn cần.
Tôi thích cái này: it - vec.begin()
vì với tôi nó nói rõ ràng "khoảng cách từ đầu". Với các trình vòng lặp, chúng ta thường nghĩ về mặt số học, vì vậy -
dấu hiệu là chỉ số rõ ràng nhất ở đây.
distance
?
it++
và không phải như thế std::increment(it)
, phải không? Điều đó cũng không được tính là ít rõ ràng hơn?
++
nhà điều hành được định nghĩa như là một phần của chuỗi STL như thế nào chúng ta tăng các iterator. std::distance
tính toán số phần tử giữa phần tử đầu tiên và phần tử cuối cùng. Thực tế là các -
nhà điều hành làm việc chỉ là một sự trùng hợp ngẫu nhiên.
Nếu bạn đã bị hạn chế / mã hóa thuật toán của mình để sử dụng một std::vector::iterator
và std::vector::iterator
chỉ, thì thực sự bạn sẽ không sử dụng phương pháp nào. Thuật toán của bạn đã được cụ thể hóa vượt quá điểm mà việc chọn một trong những thuật toán khác có thể tạo ra bất kỳ sự khác biệt nào. Cả hai đều làm chính xác cùng một điều. Nó chỉ là một vấn đề sở thích cá nhân. Cá nhân tôi sẽ sử dụng phép trừ rõ ràng.
Mặt khác, nếu bạn muốn duy trì mức độ tổng quát cao hơn trong thuật toán của mình, cụ thể là, cho phép khả năng một ngày nào đó trong tương lai nó có thể được áp dụng cho một số kiểu lặp khác, thì phương pháp tốt nhất phụ thuộc vào ý định của bạn . Nó phụ thuộc vào mức độ hạn chế mà bạn muốn liên quan đến loại trình vòng lặp có thể được sử dụng ở đây.
Nếu bạn sử dụng phép trừ rõ ràng, thuật toán của bạn sẽ bị giới hạn trong một lớp lặp khá hẹp: các trình lặp truy cập ngẫu nhiên. (Đây là những gì bạn nhận được bây giờ từ std::vector
)
Nếu bạn sử dụng distance
, thuật toán của bạn sẽ hỗ trợ một lớp các trình vòng lặp rộng hơn nhiều: các trình vòng lặp đầu vào.
Tất nhiên, tính toán distance
cho các trình vòng lặp truy cập không ngẫu nhiên trong trường hợp nói chung là một hoạt động không hiệu quả (trong khi, một lần nữa, đối với các truy cập ngẫu nhiên, nó hiệu quả như phép trừ). Tùy thuộc vào bạn để quyết định xem thuật toán của bạn có hợp lý với các trình vòng lặp truy cập không ngẫu nhiên hay không, hiệu quả. Do đó, sự mất hiệu quả dẫn đến tàn phá đến mức làm cho thuật toán của bạn hoàn toàn vô dụng, sau đó bạn nên sử dụng phép trừ, do đó cấm sử dụng không hiệu quả và buộc người dùng phải tìm giải pháp thay thế cho các loại trình vòng lặp khác. Nếu hiệu quả với các trình vòng lặp truy cập không ngẫu nhiên vẫn nằm trong phạm vi có thể sử dụng, thì bạn nên sử dụng distance
và ghi lại thực tế rằng thuật toán hoạt động tốt hơn với các trình vòng lặp truy cập ngẫu nhiên.
Theo http://www.cplusplus.com/reference/std/iterator/distance/ , vì vec.begin()
là một trình vòng lặp truy cập ngẫu nhiên , phương thức khoảng cách sử dụng -
toán tử.
Vì vậy, câu trả lời là, từ quan điểm hiệu suất, nó là như nhau, nhưng có thể sử dụng distance()
sẽ dễ hiểu hơn nếu có ai phải đọc và hiểu mã của bạn.
Tôi chỉ sử dụng -
biến thể std::vector
- nó khá rõ nghĩa là gì và tính đơn giản của thao tác (không phải là phép trừ con trỏ) được thể hiện bằng cú pháp ( distance
, mặt khác, nghe giống như tiếng pythagoras trên đọc lần đầu phải không?). Như chúBen chỉ ra, -
cũng hoạt động như một xác nhận tĩnh trong trường hợp vector
được thay đổi ngẫu nhiên thành list
.
Ngoài ra tôi nghĩ rằng nó phổ biến hơn nhiều - mặc dù không có con số để chứng minh điều đó. Đối số chính: it - vec.begin()
ngắn hơn trong mã nguồn - công việc gõ ít hơn, tiêu tốn ít dung lượng hơn. Vì rõ ràng rằng câu trả lời đúng cho câu hỏi của bạn là vấn đề của hương vị, đây cũng có thể là một lý lẽ hợp lệ.
Dưới đây là một ví dụ để tìm "tất cả" số lần xuất hiện của 10 cùng với chỉ mục. Nghĩ rằng điều này sẽ có ích.
void _find_all_test()
{
vector<int> ints;
int val;
while(cin >> val) ints.push_back(val);
vector<int>::iterator it;
it = ints.begin();
int count = ints.size();
do
{
it = find(it,ints.end(), 10);//assuming 10 as search element
cout << *it << " found at index " << count -(ints.end() - it) << endl;
}while(++it != ints.end());
}