我刚刚熟悉STL,我不太明白为什么operator []
会出错。
int main(){
set< int > s;
for(int i=0; i<=1000; i++) s.insert((i*1777)%123);
for(int i=0; i<s.size(); i++) cout<<s[i]<<endl;
}
然后我尝试了这个并得到了另一条错误消息
int main(){
set< int > s;
for(int i=0; i<=1000; i++) s.insert((i*1777)%123);
for(int i=0; i<s.size(); i++) cout<<*(s.begin() + i)<<endl;
}
我理解为什么它没有像push_back
,pop_back
这样的成员,但我不明白为什么这两种引用方法不起作用(但它们的确如此) vector
和string
)。我知道这些运算符在库中没有超载,但为什么呢?
经过一些网络搜索,我确实想出了如何引用它
int main(){
set< int > s;
for(int i=0; i<=1000; i++) s.insert((i*1777)%123);
for(set< int >::iterator i=s.begin(); i!=s.end(); i++) cout<<*i<<endl;
}
答案 0 :(得分:6)
标准没有为集合或其迭代器指定那些运算符,因为这些不是访问集合的有效方法。集合具有双向迭代器。这意味着为了移动到迭代序列中的第n个元素,您需要迭代其间的每个元素。因此,例如,如果要在内部对集合的迭代器实现operator +,则它将是这样的:
iterator operator+(iterator it, size_t n)
{
for (int i=0; i<n; ++i)
++it;
return it;
}
因此,换句话说,它将是一个O(n)操作。如果你像在for循环中那样遍历集合,那么它就变成了一个O(n ^ 2)for循环。如果operator[]
已实施,则同样适用。因此,没有一个有效率的人会想要使用这些运算符,因此它们没有实现。
答案 1 :(得分:1)
STL set不会重载下标运算符[]
。您不能像使用vector
等其他容器一样直接使用下标运算符访问STL集元素。
您可以在此处找到STL集的完整参考:STL set
答案 2 :(得分:1)
嗯,这是因为std::set
不提供下标operator[]
因为set的性质而完全可以理解的内容。应该是什么意思[4]?数学上这是不正确的。在数学中,set1 = {1,2,3,4}和set2 = {4,3,2,1}是相等的,所以如果这两组中的每两个set1 [n]和set2 [n]仍然如此是不同的(在std::set
的情况下,元素是排序的,所以它会是相同的)?因此std::set
没有下标operator[]
,但您仍然可以遍历此容器。
int myints1[]= {10,20,30,40,50};
int myints2[]= {50,40,30,20,10};
std::set<int> s1 (myints1,myints1+5);
std::set<int> s2(myints2,myints2+5); // Internally, the elements in a set are
// always sorted following a specific strict
// weak ordering criterion indicated by its
// internal comparison object, so this set
// will be the same as s2
if(s1==s2){
printf("sets: true");
}else printf("sets: false");
std::set<int>::iterator it2=s2.begin();
for(std::set<int>::iterator it1=s1.begin();it1!=s1.end();it1++){
printf("\ns1: %d s2: %d",*it1,*it2);
it2++;
}
输出:
设置:true
s1:10 s2:10
s1:20 s2:20
s1:30 s2:30
s1:40 s2:40
s1:50 s2:50
答案 3 :(得分:1)
@BenjaminLindley指出T& operator[](std::size_t)
对没有随机访问迭代器的容器没有意义,因为所有随机访问循环都具有O(N^2)
复杂度(在外部循环中线性元素,迭代器上std::advance
的线性时间。出于这个原因,序列容器,只有std::array
,std::vector
和std::deque
提供operator[]
,但std::list
(双向迭代器) )和std::forward_list
(前向迭代器)没有。
有序关联容器(std::set
,std::map
及其多个兄弟)仅提供双向迭代器和无序关联容器( std::unordered_set
,std::unorderd_map
和他们的多个表兄弟)至少有前向迭代器。他们也没有operator[](std::size_t)
成员。因此,您需要编写std::advance(my_set.begin(), n)
而不是my_set[n]
,这会使此类调用的O(N)
复杂性变得非常明显。
正如一个补充说明:类似地图的容器包含键值对,这些容器的关联性质通过另一个operator[]
表示,但不是由偏移量表示,而是用“关联”表示密钥和签名Value& operator[](Key const&)
(以及自C ++ 11以来的rvalue-reference重载)。对于O(log N)
,这些运营商的std::map
复杂度为O(1)
,std::unordered_map
的复杂度为O(N log N)
。这将给出例如分别遍历这些容器O(N)
和operator[]
复杂度的所有键。
关联my_map[my_key] = my_value;
版本也有插入语义:像my_key, my_value
这样的调用会尝试将对const
插入到地图中,并返回迭代器这样的元素已经存在。请注意,这些关联元素访问也没有find()
重载:使用std::set
成员函数。
对于operator[](Key const&)
,重载的insert()
没有任何意义,因为它只表示密钥与自身相关联的事实,并且插入语义已经通过{{更直接地表达了1}}成员函数。
答案 4 :(得分:0)
如果BST的每个节点都保持其后代的计数,则可以在O(log(n))时间内找到BST的第i个元素,并且可以在O中返回整个树的大小( 1次。每次插入和删除时的开销都是O(log(n)),这已经是O(log(n)) - 时间操作。