我和我的教授进行了以下交流,这不是很令人满意。我把交换的内容包括在内,应该足以使我明白我的观点。
“对于向量,C ++实现是否遍历旧的动态分配数组的每个元素并释放它? (编辑:我的意思是,在通过推回或调整大小来调整大小和添加元素时)
我特别好奇,因为这本书试图证明链表很麻烦,因为每次都要遍历。在我看来,向量在这方面没有巨大的优势。
我看到的向量的主要好处是方便和快速访问,但仅此而已。与之类似,每次您尝试进行除访问以外的其他操作时,您都将遍历所有内容以移动和释放内存。正确吗?”
在他回复后,我补充了。
“教授xxxx,
我去测试了,实际上,如果您调整大小或push_back,地址都会更改,因此我认为释放旧地址的假设是正确的。我只能假设程序必须转到每个元素才能释放它,如果是正确的话,那么在时间方面,插入新内容是否会比遍历链表还要花费更多时间?
如果以下陈述陈述了任何不正确的事实或假设,您是否可以更正?使用向量而不是使用数组(除访问已存储的数据以外的任何其他目的)使用向量,意味着链表几乎总是更快,因为与链表不同,在向量中,不仅要遍历元素,还要遍历向量它们,释放它们,然后创建一个全新的阵列以容纳新的空间。那是因为当前向量的最后一个元素之后的下一个地址可能有一个指向它的指针变量,并且使用该地址将导致一种极其奇怪的行为,我无法想象可怜的灵魂的痛苦试图找出问题出在哪里。 。”
TL; DR: 链表的缺点是遍历,但是向量的使用(push_back,resize()等)通常还是需要遍历的,那么向量的速度究竟如何?
答案 0 :(得分:3)
几件事比您预期的要快:
重新分配向量时,原始元素将被逐个破坏而不是释放。然后将它们的存储全部释放。这与链表相反,链表中的每个节点都是单独分配和释放的。但这有点无聊,因为:
向量批量重新分配。 std::vector
是specified,具有摊销不变的插入成本,这意味着在考虑复杂性时,此成本可以忽略不计,从而避免了每次push_back
时都进行重新分配。典型的实现是每次超出向量的容量时,都会将其容量乘以固定因子,因此在执行昂贵的重新分配时,它会为接下来的几个push_back
提供空间。这样就不需要遍历向量或分配任何东西。
向量对缓存非常友好。这样一来,向量上的所有顺序操作都将快速进行,并且在许多情况下可以直观地胜过链表,尤其是在长时间运行的应用中,内存可能会变得碎片化。
答案 1 :(得分:0)
作为已经给出的答案和评论的补充...
std::vector
的元素连续存储在内存中,而不是链表。
直接的结果是,对于std::vector
而言,元素访问是微不足道的,而对于链表则不是。
例如,如果我想访问链表的 n th 元素,则必须遍历该列表,直到到达所需的元素。
但是另一方面,如果我们想在其中插入新元素,则链表的性能会更好。
确实,对于链表,我们必须迭代直到到达所需位置,然后才需要更改上一个节点与下一个节点之间的连接,以便在其中插入新元素。
对于std::vector
,您必须将每个元素重新放置在所需位置之后(并在需要时进行重新分配,即,如果添加新元素超出了保留的可用空间)。
因此,std::vector
对于元素访问而言是更好的,但是在元素内部插入元素时的效率(与删除操作相同)。