为什么LinkedList(T)没有实现IList(T)接口?

在C#中,LinkedList(T)类不实现IList(T)接口。 但是,List(T)类确实实现了IList(T)。 为什么会出现这种差异? 从function上讲,它们都是列表,所以这个设计选择看起来很奇怪。 现在很难将实现从List(T)切换到LinkedList(T)。

IList接口包含一个索引器,索引器不是您在LinkedList上所期望的function。

List可以确保通过定义来访问O(1)LinkedList的项目,它的结构不能提供对O(1)中项目的访问。

查看链接列表的定义,您将理解。

主要问题,LinkedLists可以包含循环引用,因此没有索引。

链表是最简单和最常见的数据结构之一; 它们为几个重要的抽象数据结构提供了简单的实现,包括堆栈,队列,关联数组和符号表达式。

链接列表相对于传统arrays的主要好处是链接项的顺序可能与数据项存储在内存或磁盘上的顺序不同。 因此,链接列表允许在列表中的任何位置插入和删除节点,并且操作数量恒定。

另一方面,链表本身不允许随机访问数据或任何forms的有效索引。 因此,许多基本操作 – 例如获取列表的最后一个节点,或找到包含给定数据的节点,或者定位应插入新节点的位置 – 可能需要扫描大多数列表元素。

接口给出了三种类型的保证,1种是程序性的,2种是概念性的。

程序保证是您可以调用存在的方法或属性。 .NET强制执行此保证。

第一个概念保证是它会起作用。 这经常被破坏(NotImplementedException和NotSupportedException正好存在以打破这个),但应该有一个很好的理由这样做。 不过,这更像是承诺而非保证。

第二个概念保证也是承诺而不是保证,即方法或财产将像其他情况一样工作。

人们习惯于让IList的索引器以相当快的速度运行 – O(1)或更糟糕的O(log n) – 并打破这个概念上的承诺会导致人们严重使用你的对象。

这里没有具体的规则。 您当然可以将IList实现为链接列表,并受到O(n)索引获取。 您还可以实现链接列表,使其不保留其计数记录(由框架提供的记录)并具有O(n)Count属性。 但是人们更有可能使用它。

组件设计的一部分不仅仅是确保工作正常并且运行良好,而是指导它们的使用。 实现IList的链表在后一点会失败,因此人们可以提出一个强有力的论据,即它不会像提供的那样好。

LinkedList实际上是一个广为人知的列表数据结构,具有以下操作复杂性:

 Insertion: O(N) Removal: O(1) Indexing: O(N) 

而List是一个连续数组,具有以下算法复杂度:

 Insertion*: O(1) Removal*: O(N) Indexing: O(1) 

它们不提供通用接口,因为它会误导接口的用户并使程序效率变得不可预测。 有关更多信息,请查阅有关算法和数据结构的书籍。

LinkedList不是List。 列表是对象的单个维度集合。 LinkedList是一个节点集合,与Dictionary更紧密地对齐。 它的需求与常规List不相似,但更专业于允许节点遍历和组织行为。

“列表”是数据结构术语不是链表; 它实际上是一个数组 – 使用索引器可以直接访问列表项,索引器在链表中不可用(不实用)。

历史怪癖:在.NET 1.1中,ArrayList是一个类似于动态长度数组的类。

在.NET 2+中,List内部组织为一个数组。 这意味着IList确实需要Array语义。

在.NET中,列表就像数组 ,而不是列表…. (boing)

真正的链接列表具有恒定的时间插入,删除,但缓慢的枚举和较慢的随机访问。

数组具有快速枚举和随机访问,但具有昂贵的插入/删除(O(n)和重新分配可能会导致完全不同的行为)

这也让我感到意外。传统上,列表只是你可以依赖元素顺序的东西,链表遵循这个,它应该实现IList而不是ICollection(一个集合没有说明任何关于其元素的顺序)。

没有实现IList,因为有些操作的复杂性比某些人预期的要差,我认为这是错误的。

链表不是设计为由索引访问的数据结构,但是, IList提供索引访问function。

因此,由于您无法通过索引访问链接列表中的项目,因此无法提供尝试执行此操作的方法。

因为通过索引访问链表不是O(1)。