我正在制作一个解决此问题的程序:http://opc.iarcs.org.in/index.php/problems/BOOKLIST
我使用矢量的唯一地方是:
for(int i =0;i < total_books; i++){
int temp;
cin >> temp;
books_order.push_back(temp);
}
和
for(int i = 0;i < total_entries; i++){
int index;
cin >> index;
index--;
cout << books_order[index] << endl;
books_order.erase(books_order.begin()+index);
}
(这是我的完整代码:http://cpaste.org/1377/)
我从矢量中使用的唯一函数是vector :: erase,vector :: push_back和vector :: begin。 对于大输入,我的代码花费的时间超过3秒(这是该问题的时间限制),但是当我删除向量函数时,它运行得更快(但是给出了错误的答案)
我明白在这个问题上使用向量是错误的,我的算法很慢,但我不明白为什么它很慢。
如果您知道为什么我使用的功能很慢,请向我解释。 谢谢。
答案 0 :(得分:8)
我从向量中使用的唯一函数是vector :: erase,vector :: push_back和vector :: begin
我会说这是你的问题。 vector::erase
是O(n)
,其他是恒定时间,不应该导致在线审判问题的效率问题。避免擦除方法。
但是,一般情况下,如果您事先知道数组的大小,我会使用一个简单的数组。如果你能提供帮助,不要增加任何不必要的开销。
要解决您链接的问题,请考虑使用set:其擦除方法为O(log n)
,其插入方法也是如此。如果您需要随机删除,那么您应该使用这一点。
编辑:我忘记了C ++也有priority queues,所以也要考虑一下。既然你只关心这里的最大值,它可能比一个集合更快,虽然它们都具有相同的理论复杂性(一堆可以检索 O(1)
中的最小值/最大值,但是删除对于这个问题你必须做的是O(log n)
),在这种情况下,任何一个都可以正常工作。
答案 1 :(得分:7)
IMO的罪魁祸首是vector::erase
,因为它将移除所有元素之后的所有元素。因此,除非你总是删除最后一个元素,否则它可能会很慢。
答案 2 :(得分:3)
除非您已调用reserve
来将向量调整为您拥有的元素数量,否则每次新大小超过向量容量时,对push_back
的调用都将重新分配内存。考虑使用reserve
为您的元素分配足够的内存,您应该看到性能加快,特别是如果向量很大。另请注意有关使用erase
的其他答案。
答案 3 :(得分:2)
从向量中间删除元素(使用vector::erase
)很慢。这是因为向量的所有较高元素必须向下移动以填充您已移除的元素留下的间隙。
因此,这不是矢量缓慢的情况,但是由于您选择了不适当的数据结构,因此算法速度很慢。
答案 4 :(得分:2)
你的问题是要求“擦除”。如果您查看文档here,则会注意到:
因为向量保持数组格式,所以擦除除向量末端以外的位置也会将段擦除后的所有元素移动到新位置,这可能不像在其他类型的序列容器中擦除那样有效(deque ,列表)。
从结束运行循环或循环后擦除。
答案 5 :(得分:1)
如果您事先知道向量中有一定数量的元素,则可以保留足够的空间来包含所有内容,以便在向量中保存自己的空间重新分配:
books_order.reserve(total_books)
for(int i=0 ;i < total_books; ++i){
int temp;
cin >> temp;
books_order.push_back(temp);
}
然而,这不是问题所在,我相信如果您对代码进行了分析,您会发现.erase()
用法会产生很大的开销。从向量中间移除元素很慢,因为向量的实现方式需要将所有元素移动到被移除的元素中。请考虑使用其他数据结构,例如std::array
。
答案 6 :(得分:0)
你真的需要一个向量来实现你正在做的事情吗?
你必须记住向量是如何工作的:它们本质上是动态数组,当你在其中添加更多项时会调整大小。调整向量的大小是O(n)操作(其中n是向量中的项目数),因为它分配新内存并将项目复制到新向量。
您可以在here了解哪些向量是好的。
我建议使用标准数组 - 这似乎完全合理,因为你已经知道有多少总元素(total_books
)