2013-12-09 13 views
16

Tôi đã tình cờ gặp vấn đề này: Tôi dường như không thể chọn mục ở vị trí của chỉ mục trong tập lệnh std bình thường ::. Đây có phải là lỗi trong STD không?Phần tử tại chỉ mục trong tiêu chuẩn :: được đặt?

Dưới đây là một ví dụ đơn giản:

#include <iostream> 
#include <set> 

int main() 
{ 
    std::set<int> my_set; 
    my_set.insert(0x4A); 
    my_set.insert(0x4F); 
    my_set.insert(0x4B); 
    my_set.insert(0x45); 

    for (std::set<int>::iterator it=my_set.begin(); it!=my_set.end(); ++it) 
     std::cout << ' ' << char(*it); // ups the ordering 

    //int x = my_set[0]; // this causes a crash! 
} 

Bất cứ điều gì tôi có thể làm gì để khắc phục vấn đề?

+4

'my_set [0]' không được biên dịch. – chris

+2

Bạn đang đặt câu hỏi sai, vì bạn đang sử dụng vùng chứa sai. Mỗi thùng chứa tiêu chuẩn đã được thiết kế với một số lượng sử dụng nhất định trong tâm trí, và lần lượt không cho phép người khác (trực tiếp). Vì vậy, trước tiên, bạn cần phải xác định những hoạt động bạn cần và sau đó [chọn đúng container] (http://stackoverflow.com/questions/10699265/how-can-i-efficiently-select-a-standard-library- container-in-c11/10701102 # 10701102) –

+0

Bản sao có thể có của [Lấy phần tử từ chỉ mục tùy ý trong tập hợp] (http: // stackoverflow.com/questions/8907435/get-element-from-arbitrary-index-in-set) –

Trả lời

39

Nó không gây ra sự cố, nó chỉ không biên dịch. set không có quyền truy cập theo chỉ mục.

Bạn có thể lấy yếu tố thứ n như thế này:

std::set<int>::iterator it = my_set.begin(); 
std::advance(it, n); 
int x = *it; 

Giả sử my_set.size() > n, tất nhiên. Bạn nên biết rằng hoạt động này cần thời gian xấp xỉ tỷ lệ thuận với n. Trong C++ 11, có cách viết đẹp hơn:

int x = *std::next(my_set.begin(), n); 

Một lần nữa, bạn phải biết rằng n là giới hạn đầu tiên.

+0

Tất nhiên, nếu OP dự kiến ​​'my_set [0]' để trả về '0x4A', điều này vẫn sẽ không làm những gì mong muốn. – Useless

+3

@Không có ích: đúng. Nhưng nếu họ mong đợi nó trả lại giá trị đầu tiên từ vòng lặp trước đó trong mã của họ thì chúng tốt. Nói chung, nếu người hỏi không biết 'bộ' là gì thì họ sẽ thấy một loạt các kết quả đáng ngạc nhiên cho đến khi họ cuối cùng bỏ cuộc và RTFM ;-p –

+0

Xin lỗi vì điều này, nhưng câu hỏi được cho là một trò đùa (các giá trị là mã hex ASCII cho "JOKE", suy nghĩ thiết lập là không có thứ tự, do đó lặp đi lặp lại sẽ không mang lại kết quả tương tự). Tuy nhiên, tôi không biết về std :: advance hoặc std :: tiếp theo, vì vậy cảm ơn bạn đã chia sẻ điều đó! – hauron

4

Một thực hiện thông thường của std::set là sử dụng binary search trees, đáng chú ý self-balancing binary search trees như red-black trees

Họ không cung cấp cho bạn truy cập thời gian liên tục tới phần tử n-thứ. Tuy nhiên, bạn dường như muốn đầu tiên. Vì vậy, hãy thử trong C++11:

auto it = my_set.begin(); 
int first=0; 
if (it != my_set.end()) first = *it; 
+0

Cảm ơn bạn đã trả lời câu hỏi này - xin lỗi vì điều đó - câu hỏi đùa. Tuy nhiên, từ C++ 11 mã của bạn chỉ có vẻ mang ý nghĩa mới của 'tự động'. – hauron

0

Đây không phải là lỗi trong STD. Không có quyền truy cập ngẫu nhiên trong một số std::set. Nếu bạn cần truy cập ngẫu nhiên theo chỉ mục, bạn có thể sử dụng std::vector

+1

Vâng, có. Theo mặc định, nó sử dụng 'std :: less' để sắp xếp thứ tự. – chris

+0

Bạn nói đúng, tôi đã nghĩ đến 'std :: unordered_set'. Đã chỉnh sửa –

+1

Đơn đặt hàng không phụ thuộc vào việc triển khai. Như Chris nói, nó sử dụng 'std :: less' trừ khi được nói khác đi, trong trường hợp' int' chỉ là một cách ưa thích để nói '<'. –

0

Đôi khi có một lý do chính đáng để bạn có thể lập chỉ mục. Gần đây, tôi đã phải triển khai chức năng này để hỗ trợ API cũ có chức năng trả về số mục và mục tại chỉ mục để người gọi có thể liệt kê các mục.

Cách giải quyết vấn đề của tôi là sử dụng std :: vector và sử dụng std :: equal_range để tìm và chèn hoặc xóa các mục trong tập hợp. Ví dụ, chèn một mục mới vào các thiết lập như sau:

std:vector<std::string> my_set; 

    ... 

    std::string new_item("test"); 

    auto range = std::equal_range(my_set.begin(),my_set.end(),new_item); 
    if (range.first == range.second) 
     my_set.insert(range.first,new_item); 

Xóa rất giống: sử dụng equal_range để tìm mặt hàng đó, và nếu range.first là không bằng range.second, xóa phạm vi.

-2
std::set<int> my_set; 
    my_set.insert(0x4A); 
    my_set.insert(0x4F); 
    my_set.insert(0x4B); 
    my_set.insert(0x45); 

    int arr[my_set.size()]; 

    set<int>::iterator it = my_set.begin(); 
    for (int i = 0; i < my_set.size(); i++) { 
    arr[i] = *it; 
    it++; 
    } 
    cout << arr[0]; 

Chỉnh sửa: Mã đã chỉnh sửa. Bạn không thể truy cập thiết lập bằng cách sử dụng chỉ mục nhưng phương pháp trên sẽ cung cấp một "chỉ mục" i nếu bạn muốn sao chép các phần tử được đặt thành một mảng, miễn là bạn đã tạo một mảng có kích thước đủ trước khi tay.

+0

Cách này trả lời câu hỏi? Bạn chỉ đang lặp qua bộ này theo cách hơi khác. – cpburnz

+0

@cpburnz Không có câu trả lời nào khác lặp lại một tập hợp với chỉ mục. Có một sử dụng để lặp lại một tập hợp bằng cách sử dụng chỉ mục như trong ví dụ của tôi. – katta

Các vấn đề liên quan