fiktor
fiktor

Reputation: 1413

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. That is, I want to store elements 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 (i.e. access to v[0], then v[1] and so on with the ability to edit the values);
  2. Point relocation, i.e.

    {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, i.e.

    {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). But I know, that XOR-linked list is considered to be "an ugly data structure" ([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?

Upvotes: 3

Views: 725

Answers (2)

Mikael Persson
Mikael Persson

Reputation: 18572

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).

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.

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. 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).

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 (e.g. 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)

Upvotes: 1

Timothy Shields
Timothy Shields

Reputation: 79521

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.

  1. Sequential access of std::vector<T> is extremely efficient.
  2. The std::rotate algorithm will work for operation 2.
  3. The std::reverse algorithm will work for operation 3.

The mentioned algorithms are in the <algorithm> header.

Upvotes: 0

Related Questions