2

I have some list that I want to iterate through, sometimes from start to end, sometimes from end to start. This list is never modified and I will iterate through it multiple times. I would like to avoid the operation of reversing the list in O(n) when I want to iterate from end to start.

Is there some data structure that allows that?

I was thinking that it would be simple for the (doubly) LinkedList implementation in C# to allow this behavior (by keeping an internal reference of what is the start of the list), but I don't think it is implemented that way. Can you provide a link if I am wrong.

Jason
  • 3,777
  • 14
  • 27
Gradient
  • 2,253
  • 6
  • 25
  • 36
  • 4
    You can iterate forward and backward using an array. – Jason Oct 25 '19 at 00:47
  • For that matter you can iterate anything forward and backward as long as it has an integral keyed indexer and a `Count` field. – Patrick Roberts Oct 25 '19 at 00:52
  • Clearly not covering all possibilities but there are plenty of samples for list/array in [reverse foreach](https://stackoverflow.com/questions/1211608/possible-to-iterate-backwards-through-a-foreach) question... – Alexei Levenkov Oct 25 '19 at 00:53
  • Can you advise what troubles you've encountered finding such a structure? For example, why are Array, List, etc. not suitable? – ProgrammingLlama Oct 25 '19 at 00:58
  • Most of the time, you can simply keep a bool `curOrder` and usw it to choose `a[i]` or `a[n-i-1]` when iterating. In more complicated cases (say, reversing multiple subsegments), treaps can sometimes be used. – the default. Oct 25 '19 at 00:59

1 Answers1

6

Any data structure with direct indexed access and length (arrays, lists, strings, file streams) allow representation of completing "reverse" in O(1) time (note that it's reverse itself, obviously iterating all items will still be O(n).

There are several examples in Possible to iterate backwards through a foreach? with "yield return" suggested by Jon Skeet is the most flexible way (likely a bit less performant that just backward for):

public static IEnumerable<T> FastReverse<T>(this IList<T> items)
{
    for (int i = items.Count-1; i >= 0; i--)
    {
        yield return items[i];
    }
}

As Patrick Roberts commented you can also use other data structure that looks like array - i.e. dictionary with sequential int keys and known high/low boundaries would work (which is roughly how JavaScript arrays work).

Indeed double-linked-list (LinkedList in C#) is the data structure of choice when only forward and reverse iterations are needed... but converting array/list (that already give you O(1) way to represent reverse iteration) is not worth it. Depending on other requirements switching to linked list completely may be an option.

Note that from theoretical point of view if you need to iterate through all elements anyway then spending O(n) on reverse does not change overall complexity.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179