tags:

views:

232

answers:

8

In C#, the LinkedList(T) class does not implement the IList(T) interface. However, the List(T) class does implement IList(T). Why is there this discrepancy? Functionally, they are both lists, so this design choice seems odd. It now becomes difficult to switch implementations from List(T) to LinkedList(T).

+6  A: 

See the definition of a linked list, and you will understand.

Main issue, LinkedLists can contain circular references, and thus does not have an index.

Linked lists are among the simplest and most common data structures; they provide an easy implementation for several important abstract data structures, including stacks, queues, associative arrays, and symbolic expressions.

The principal benefit of a linked list over a conventional array is that the order of the linked items may be different from the order that the data items are stored in memory or on disk. For that reason, linked lists allow insertion and removal of nodes at any point in the list, with a constant number of operations.

On the other hand, linked lists by themselves do not allow random access to the data, or any form of efficient indexing. Thus, many basic operations — such as obtaining the last node of the list, or finding a node that contains a given datum, or locating the place where a new node should be inserted — may require scanning most of the list elements.

Arcturus
I disagree with the idea that they're the simplest *or* most common data structures. They're a pain in the ass to implement on your own, and have all kinds of issues you have to account for. And I barely ever see them implemented. Stacks are frequently used and very easy to implement on the other hand.
Jimmy Hoffa
But that doesn't preclude accessing by index. If you define the indexer such that each successive "hop" in the list decrements the index, then you'd have an indexer. A very inefficient indexer, but an indexer. Hence, I think indexers aren't implemented on a linked list to prevent you from shooting yourself in the foot, much like they're not supported directly for `IEnumerable<T>`.
Kent Boogaart
Well the idea is pretty simple, isn't it? Let each node link to its neightbor, and you have yourself a list :). About most common I agree: I never use LinkedLists!
Arcturus
@Kent: Building your own index that way would also be pretty useless with a circular reference. ;)
Arcturus
The LinkedList class can prevent you from creating circular references. If you don't have access to the list's nodes, then you cannot do anything the LinkedList does not allow.
Michael Venable
@Jimmy Hoffa: A stack is often implemented using a LinkedList with the push and pop methods implemented using FILO.
Wix
@Arcturus: What if I wanted a cyclic data structure where all I had to do was increment the index, and it would automatically wrap around to get me the next item? That would be useful. The point is the indexer could work and have well-defined behavior. What it wouldn't have is acceptable performance.
Kent Boogaart
@Wix: and because all you have for accessors are push and pop, the the implementation becomes far easier in a stack as you don't have to account for all the edge cases involved in the rest of the functionality a traditional linked list provides.
Jimmy Hoffa
@Kent: That would be true. But if you would not expect it, it would probably be hard to detect, with terrible performance as well ;)
Arcturus
@Arcturus: that's the point :) If the performance of indexing on a linked list was guaranteed *O(1)*, I think it would certainly be provided - even for the circular case.
Kent Boogaart
+18  A: 

IList<T> interface contains an indexer, the indexer is not a functionality you expect on a LinkedList.

List<T> can assure access to items in O(1), LinkedList by definition of it's it structure can't provide access to items in O(1).

Elisha
Thank you, everyone, for your answers. I overlooked that the definition of an IList is "Represents a collection of objects that can be individually accessed by index." It doesn't match up with my idea of a list, but hey, it's their language, they can choose the definitions.Many people have claimed that linked lists cannot support indexing, however the Java language's linked list does indeed have indexes (their documentation makes no claim on it's time-efficiency).
Michael Venable
I ran into this problem once, and ended up making my own IndexedLinkedList class (yeah, it sounds stupid, but was the best option). It's good to keep track of the differences.
NickAldwin
+1  A: 

Because accessing a linked list by index is not O(1).

HTH,
Kent

Kent Boogaart
A: 

A linked list is not a data structure that is designed to be accessed by index, however, IList<T> provides index access capabilities.

So, as you can't access items in a linked list by index, you can't provide methods that try to do that.

Oded
A: 

A "List" is data structure terms is not a linked list; it's actually an array -- List item are directly accessible, using the indexer, which is not available (not practical) in a linked list.

James Curran
A: 

The LinkedList is not a List. Lists are singular dimensional collections of objects. A LinkedList is a node collection, more closely aligned with a Dictionary. Its needs are not similar to a regular List but more specialized to allow for the node traversal and organization behaviors.

Joel Etherton
+3  A: 

LinkedList is actually a widely-known list data structure which has following operation complexity:

Insertion: O(1)

Removal: O(1)

Indexing: O(N)

Whereas List is a continuos array, which has following algorithm complexity:

Insertion*: O(1)

Removal*: O(N)

Indexing: O(1)

They do not provide the common interface, cause it will misguide users of the interface and make programs efficiency unpredictable. For more information check out books on algorithms and data structures.

Grozz
Insertion is O(N) for lists.
Jason
@Grozz, yes, @Jason is right, insertion is O(N) - indeed it's amortised O(N). Appending is amortised O(1). Interestingly enough insertion-at-index is O(N) for a linked list but amortised O(N) for List.
Jon Hanna
+1  A: 

There are three types of guarantee given by an interface, 1 programmatic and 2 conceptual.

The programmatic guarantee is that you can call a method or property that exists. .NET enforces this guarantee.

The first conceptual guarantee is that it will work. This is often broken (NotImplementedException and NotSupportedException exist precisely to break this) but there should be a good reason for doing this. Still, it's more a promise than a guarantee.

The second conceptual guarantee is also more a promise than a guarantee, which is that the method or property will work much like other cases.

People are used to getting on an IList's indexer working in reasonably fast - O(n) or at worse about O(log n) - and breaking that conceptual promise will lead to people using your object badly.

There's no concrete rule here. You certainly can implement IList as a linked list, and suffer the O(n) indexed get. You can also implement a linked list in such a way that it doesn't keep a record of its count (as that supplied by the framework does) and have an O(n) Count property. But then people are more likely to use it badly.

Part of component design is not just making sure things work and work well, but guiding their use. A linked list that implements IList would fail at the latter point, and hence one could make a strong argument that it would not be as good a design as that offered.

Jon Hanna
Thanks for your detailed reply. I could talk design all day. I made a comparison to Java earlier and mentioned that Java linked lists support indexes. It seems the key distinction is that the indexer in .NET is a property and properties, in general, are not expected to do long computations. Java doesn't have properties nor does it obey their conventions, so their linked list indexer probably runs in O(n). Too bad...it would be nice to switch my list implementation based on which I thought was more efficient for the job; easier to do if they share the IList interface.
Michael Venable
There's nothing to stop you wrapping a linked-list in something that supports IList, though I would disagree because I agree with the reasoning behind it not supporting it by default. Likewise, if LinkedList really is more efficient for a job, it's likely a job that is best done without use of IList.
Jon Hanna