Một số vùng chứa STL như std::list
và std::vector
không có phương thức find()
làm hàm thành viên. Tại sao vậy? Tôi biết rằng có thay thế bằng cách sử dụng std::find
từ <algorithm>
nhưng vẫn sử dụng này không phải là 100% tự nhiên.một số thùng chứa trong stl không có chức năng tìm kiếm
Trả lời
Vì có chức năng std::find
từ algorithm
áp dụng cho chúng.
Nói chung, các vùng chứa như std::vector
và std::list
có độ phức tạp về thời gian tìm kiếm tuyến tính. Như vậy gắn với họ một thành viên find
chức năng là một sự thừa vì đã có std::find
. Đối với các vùng chứa khác (ví dụ: std::set
hoặc std::map
v.v.) có cách tốt hơn (tức là, nhanh hơn độ phức tạp tuyến tính) để triển khai tìm kiếm. Như vậy những người triển khai thực hiện thuật toán tìm kiếm nhanh hơn này như các hàm thành viên.
Vùng chứa có tính năng tìm kiếm bằng khóa sẽ được tích hợp phương pháp tìm kiếm (ví dụ: map được triển khai bên trong bằng cây nhị phân có thể tra cứu hiệu quả).
Những người khác, như những người bạn trích dẫn, sẽ cho phép một phạm vi tìm kiếm với std::find nhưng không có một chức năng tìm đặc trưng vì nó sẽ có không có lợi thế so với thuật toán std :: tìm (trừ được sắp xếp/đặc biệt trường hợp)
Theo ý kiến của tôi không thực sự trả lời câu hỏi. Câu trả lời có thể nằm trong thông số kỹ thuật ... – Theolodis
@ Theolodis lý do chính vừa được thêm vào và in đậm –
Nguyên tắc thiết kế chung là sử dụng std::find
nếu có thể và thực hiện các chức năng thành viên find
khi hiệu quả hơn.
Các container mà làm có thành viên find
là container trong đó có một yếu tố nhìn lên cơ chế hiệu quả hơn thì việc tìm kiếm tuyến tính thực hiện trong std::find
. Ví dụ: cây tìm kiếm nhị phân chẳng hạn như std::set
và std::map
hoặc bảng băm như đối tác unordered
của chúng.
Sử dụng cùng chức năng cho các vùng chứa khác nhau làm cho API rõ ràng hơn, bạn không phải tìm hiểu tính đặc thù của mỗi vùng chứa, chỉ cách áp dụng một hàm mà bạn sử dụng cho tất cả.
Nó cũng cho sử dụng lại mã - bạn sử dụng các thuật toán mà có lặp từ bất kỳ container mà cung cấp cho họ, vì vậy các thuật toán không phải dựa trên thùng sơn là một std::vector
, std::list
, vv
như vậy các vùng chứa là std::vector
, std::list
, std::forward_list
và một số khác là các vùng chứa tuần tự. Không có gì tốt hơn so với tìm kiếm tuần tự có thể được áp dụng cho các thùng chứa này. Vì vậy, không cần phải viết lại tìm kiếm tuần tự cho mỗi vùng chứa tuần tự nếu nó giống nhau cho tất cả các vùng chứa này.
Ngoại lệ là lớp std::basic_string
ban đầu mô phỏng các chuỗi C đã có các chức năng tìm kiếm đặc biệt như strchr, strstr và các chức năng khác.
find
, lower_bound
và upper_bound
chức năng thành viên chỉ được cung cấp khi hiệu quả hơn hơn bằng cách sử dụng tương đương phi thành viên, hoặc khi không phải là thành viên không thể hoạt động cho API công cộng của container
Lưu ý rằng std::string
có chức năng find
cung cấp std::find()
giống như các cơ sở tìm kiếm tuyến tính cho tìm kiếm ký tự và std::search()
các cơ sở giống như dành cho chuỗi con arches: trong khi các phiên bản không phải là thành viên có thể có hiệu quả lớn-O, chúng cũng có thể kém hiệu quả hơn với các hướng dẫn mã máy chuyên dụng thường có sẵn cho tìm kiếm "chuỗi". Ngoài ra còn có các yếu tố lịch sử, tiện lợi và dễ dàng chuyển đổi.
Khá ngoài các vấn đề về hiệu quả, đó là cần lưu ý rằng một số container:
vốn đã hoặc sắp xếp (
multi
-set
,map
) hoặc không được phân loại (unordered_map
,unordered_set
), thường không được phân loại (ví dụstd::string
) hoặc dễ dàng hoặc là (std::vector
)hỗ trợ công khai chuyển tiếp lặp lại và/hoặc truy cập ngẫu nhiên
thể tư nhân hỗ trợ tìm kiếm nhị phân
có một API công cộng chuyên ngành để truy cập yếu tố đó tái sử dụng tiềm năng của thuật toán là tương đối giới hạn (ví dụ
unordered_map::bucket
/::begin(n)
et al)
Nó cũng quan tâm rằng tìm kiếm trong một vector
thể được thực hiện bằng cách sử dụng nhiều thuật toán lớn:
std::find
hiện một brute force tuyến tính O (n) tìm kiếm mà trước tiên sẽ "tìm" các phần tử chỉ mục thấp hơn,std::binary_search
yêu cầu phải có một vector được sắp xếp nhưng nhảy xung quanh để đạt được độ phức tạp O (log2n).tùy chọn khác như tìm kiếm ngoại suy và băm có thể được áp dụng
Làm thế nào bạn sẽ chọn để thực hiện và bổ sung làm thành viên? Có vẻ hơi tùy ý. Tuy nhiên, lựa chọn sử dụng có thể là yếu tố quan trọng về hiệu năng: đối với hàng triệu yếu tố, trung bình một nửa triệu so sánh phần tử trước một trận đấu và toàn bộ triệu khi phần tử không có, trong khi đó, binary_search
thường mất ~ 20 so sánh đường.
Các container với find
thường không cung cấp sự linh hoạt như vậy, và find
và/hoặc lower_bound
/upper_bound
họ cung cấp có thể được xem như thay thế cho các khoản tương đương phi thành viên, và có khả năng cách hợp lý duy nhất để tìm kiếm các container.
Như đã đề cập trong các nhận xét khác, lý do thiết kế là vector::find()
có thể được triển khai hiệu quả như chức năng không phải là thành viên std::find()
. Lợi ích của việc sử dụng thứ hai là nó tách rời các cấu trúc dữ liệu và các toán tử hoạt động trên cấu trúc dữ liệu, làm tăng khả năng bảo trì (điều này thuận lợi cho các nhà phát triển của thư viện).
Tuy nhiên, lợi ích của trước đây là nó sẽ làm cho API giữa tất cả các vùng chứa nhất quán và làm cho mã khách hàng ít tiết hơn. Điều này sẽ làm tăng khả năng học và dễ đọc (điều này thuận lợi cho người dùng thư viện). Ngoài ra, API nhất quán sẽ cho phép viết mã chung. Xem xét việc này:
template <typename Container, typename T>
void foo(const Container& c, const T& x) {
if (std::find(c.begin(), c.end(), x) != c.end()) {
// ...
}
}
Trên đây là không hiệu quả khi Container
là một std::map
hoặc std::set
. Để làm cho nó hiệu quả, chúng ta cần phải làm:
template <typename Container, typename T>
void foo(const Container& c, const T& x) {
if (c.find(x) != c.end()) {
// ...
}
}
Nhưng sau đó nó không biên dịch cho std::vector
và std::list
. Điều này đặt ra gánh nặng cho người sử dụng thư viện để viết hàm tổng quát của mình bằng tay chuyên/quá tải đối với từng loại họ muốn hỗ trợ:
template <typename T>
bool contains(const std::vector<T>& c, const T& x) {
return std::find(c.begin(), c.end(), x) != c.end();
}
template <typename T>
bool contains(const std::set<T>& c, const T& x) {
return c.find(x) != c.end();
}
template <typename Container, typename T>
void foo(const Container& c, const T& x) {
if (contains(c, x)) {
// ...
}
}
Tôi xác nhận rằng thực hiện các loại quyết định thiết kế là khó khăn, nhưng quan điểm của tôi là các nhà thiết kế của STL đã phạm sai lầm ở đây. Các gánh nặng bảo trì rất nhỏ có vẻ khá phần lớn đáng giá hơn API và nhất quán cho người dùng. Tóm lại, vì find
phải là một hàm thành viên cho một số vùng chứa (để thực hiện), sau đó find
phải là một hàm thành viên cho tất cả các vùng chứa (để nhất quán). Lưu ý rằng tôi hoàn toàn ổn với các thuật toán khác là các hàm không phải là thành viên.
(Ý tôi là, thôi nào, một thùng chứa theo định nghĩa một cái gì đó có chứa nội dung. Sẽ không quan trọng để người dùng viết một hàm "chứa" chung và hiệu quả. Thực tế, tôi cho rằng nó nên được thêm vào
- 1. Có thùng chứa được sắp xếp trong STL
- 2. Có một thuật toán STL để tìm xem liệu một phần tử có trong một thùng chứa dựa trên một số dung sai không?
- 3. Tham số cho chức năng tìm kiếm
- 4. Đối tượng kinh doanh - Thùng chứa hoặc chức năng?
- 5. chức năng tìm kiếm()?
- 6. Có thể soạn các thuật toán STL không có một thùng chứa trung gian
- 7. Tìm kiếm chức năng PostMessage trong Qt
- 8. Con trỏ có được phép làm khóa trong các thùng chứa STL đã đặt hàng không?
- 9. Chức năng truy cập cho các thùng chứa có std :: unique_ptr
- 10. Có thể cải thiện tiệm cận của các thùng chứa chức năng không?
- 11. Tìm kiếm các chức năng trong một gói
- 12. Thùng chứa làm tổ trong thùng chứa đựng đồ chứa
- 13. jpa không có thùng chứa
- 14. Truy xuất chức năng so sánh của thùng chứa với một trình lặp vòng
- 15. Concept trên Tìm kiếm Chức năng
- 16. Cách tìm kiếm phần tử trong danh sách stl?
- 17. Tìm kiếm không xảy ra trong thùng rác tạp hóa
- 18. Tại sao các hàm thành viên trao đổi trong các thùng chứa STL không được khai báo không nhận diện?
- 19. Chức năng ref và cref STL
- 20. Có thể chạy kubernetes như một thùng chứa docker không?
- 21. Chức năng tìm kiếm nâng cao trong Doxygen?
- 22. Tìm Tham số Chức năng Dll
- 23. chức năng tìm kiếm bằng cách sử dụng rơle
- 24. Việc chuyển vùng chứa STL có tạo bản sao không?
- 25. hỗ trợ trình biên dịch cho các bộ phân bổ stateful trong các thùng chứa STL
- 26. Tìm cách tìm một vector C++ STL bên trong một vector STL
- 27. Có chức năng tìm kiếm toàn bộ từ hiệu quả trong Delphi không?
- 28. Có thể thay đổi ngày trong thùng chứa docker không?
- 29. Gọi một chức năng dựa trên một chuỗi có chứa tên chức năng
- 30. Có chức năng "tìm tất cả" tốt trong Eclipse không?
Có lẽ vì tìm kiếm một phần tử trong các chuỗi liên tục, tất cả đều có một số thuật toán, do đó, nó được tạo ra phổ biến, chơi xung quanh với vòng lặp – P0W
@POW không ngăn tiêu chuẩn thực hiện 'tìm() ', phải không? Tôi có nghĩa là nó chỉ có thể là một cuộc gọi đến 'std :: find()' ... – Theolodis
Bạn có thể muốn đọc [bài viết này của Steve Myers về việc đóng gói] (http://www.drdobbs.com/cpp/how- non-member-functions-improve-encapsu/184401197) và [GotW by Herb Sutter về 'std :: string'] (http://www.gotw.ca/gotw/084.htm). Về cơ bản, bạn càng có thể thực hiện nhiều chức năng của lớp bên ngoài giao diện trực tiếp của lớp đó, tốt hơn. – Angew