简体   繁体   English

快速插入+删除和部分反转的良好数据结构是什么?

[英]What is a good data structure with fast insertions+deletions and partial reversing?

I am writing an algorithm in C++, and for that I need a data structure to store a sequence of n data points. 我正在用C ++写算法,为此,我需要一个数据结构来存储n数据点的序列。 That is, I want to store elements v[0],v[1],...,v[n-1] . 也就是说,我要存储元素v[0],v[1],...,v[n-1] I do care about the order. 我很在意订单。

The operations I would like to be fast are: 我想快速执行的操作是:

  1. Sequential access (ie access to v[0] , then v[1] and so on with the ability to edit the values); 顺序访问(即访问v[0] ,然后访问v[1]等,并具有编辑值的能力);
  2. Point relocation, ie 点重定位,即

    {v[0],v[1],...,v[i],v[i+1],...,v[j-1],v[j],v[j+1],...,v[n-1]} -> {v[0],v[1],...,v[i],v[j],v[i+1],...,v[j-1],v[j+1],...,v[n-1]} ; {v[0],v[1],...,v[i],v[i+1],...,v[j-1],v[j],v[j+1],...,v[n-1]} -> {v[0],v[1],...,v[i],v[j],v[i+1],...,v[j-1],v[j+1],...,v[n-1]}

  3. Partial reversion, ie 部分还原,即

    {v[0],...,v[i],v[i+1],...,v[j-1],v[j],v[j+1],...,v[n-1]} -> {v[0],...,v[i],v[j],v[j-1],...,v[i+1],v[j+1],...,v[n-1]} . {v[0],...,v[i],v[i+1],...,v[j-1],v[j],v[j+1],...,v[n-1]} -> {v[0],...,v[i],v[j],v[j-1],...,v[i+1],v[j+1],...,v[n-1]}

It seems, that I can implement my algorithm using a XOR-linked list , and it will give the smallest complexity (operations above will be O(1) , giving O(n^2) for my algorithm). 看来,我可以使用XOR链接列表来实现我的算法,这将使复杂度最小(上面的操作将为O(1) ,对于我的算法为O(n^2) )。 But I know, that XOR-linked list is considered to be "an ugly data structure" ( [1] , [2] ). 但是我知道,异或链接列表被认为是“丑陋的数据结构”( [1][2] )。

What is a good data structure for this than? 为此,什么是好的数据结构? More precisely, is there any other commonly used data structure, implementing these operations in O(1) time? 更准确地说,是否还有其他常用数据结构在O(1)时间内实现这些操作?

It depends on a lot more factors that you have not mentioned. 这取决于您未提及的更多因素。

First, it depends on the size of your elements and their copying code. 首先,它取决于元素的大小及其复制代码。 If you have small elements (about 64 bytes or less) and that their copying (or moving) is cheap (or even, trivial (in the POD-type sense)), then using std::vector is likely to be a very good choice, even with the "worse" time complexities (btw, as a tip for the future, don't be too hung up on the pursuit of minimal time complexity, it's only one part of the whole story). 如果您有小的元素(大约64个字节或更少),并且它们的复制(或移动)很便宜(甚至是微不足道的(在POD类型意义上)),那么使用std::vector可能是一个很好的选择选择,即使时间复杂度“更差”(顺便说一句,作为对未来的提示,不要过于追求最小时间复杂度,这只是整个故事的一部分)。

This is especially true if your elements are trivial , because the rotate operation in a vector is going to be very fast (although still O(n)), while the other operations are the same in terms of time complexity compared to a linked-list. 如果您的元素是微不足道的 ,则尤其如此,因为向量中的旋转操作将非常快(尽管仍为O(n)),而其他操作在时间复杂度方面与链接列表相比是相同的。

Second, it depends on how often you do the different operations that you mentioned. 其次,这取决于您执行提到的不同操作的频率。 Sequential access through a linked-list is really inefficient, and they are generally not recommended if traversals are something you do often. 通过链表进行顺序访问确实效率很低,如果经常进行遍历,通常不建议使用它们。

If your elements are so small that you consider using a XOR-linked-list (to spare one pointer per element), then it's likely that you shouldn't be using a linked-list at all. 如果元素太小,以至于您考虑使用XOR链表(为每个元素保留一个指针),那么您根本就不应该使用链表。 And to be honest, I'm not sure the XOR-linked-list is ever really worth it (but I don't want to get into that). 老实说,我不确定XOR链接列表是否真的值得(但我不想涉足)。

Overall, I would have to say that you should test these three options: linked-list (either std::forward_list or std::list ), std::vector , or a vector of pointers (eg std::vector< std::unique_ptr<T> > ). 总体而言,我不得不说您应该测试这三个选项:链表( std::forward_liststd::list ), std::vector或指针向量(例如std::vector< std::unique_ptr<T> > )。 Another choice might be an unrolled linked-list , but that will only be good within a specific regime of the factors that I mentioned. 另一个选择可能是展开的链表 ,但这仅在我提到的因素的特定范围内是好的。

And I reiterate, I said test them, because that is really the only way you will know what is best. 我重申,我说过要测试它们,因为这实际上是您知道最佳方法的唯一途径。 "Analysis" is only for rules of thumb, no more, as per one of my favorite quotes: 根据我最喜欢的报价之一,“分析”仅适用于经验法则:

As far as the laws of mathematics refer to reality, they are not certain; 至于数学定律所指的是现实,还不确定。 as far as they are certain, they do not refer to reality. 据他们所知,它们并不是指现实。 (Albert Einstein) (艾尔伯特爱因斯坦)

I would just use a std::vector<T> , then only look for a potentially more efficient data structure if you find the operations are too expensive in practice. 我只使用std::vector<T> ,然后仅在发现操作实际上过于昂贵的情况下才寻找可能更有效的数据结构。

  1. Sequential access of std::vector<T> is extremely efficient. std::vector<T>顺序访问非常高效。
  2. The std::rotate algorithm will work for operation 2. std::rotate算法将适用于操作2。
  3. The std::reverse algorithm will work for operation 3. std::reverse算法将适用于操作3。

The mentioned algorithms are in the <algorithm> header . 提到的算法在<algorithm>标头中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM