在C#中创建循环链表?

在C#中创建循环链表的最佳方法是什么? 我应该从LinkedList 集合中派生出来吗? 我打算使用这个链接列表创建一个简单的地址簿来存储我的联系人(这将是一本糟糕的地址簿,但我不在乎因为我将是唯一一个使用它的人)。 我主要只想创建关键链表,以便我可以在其他项目中再次使用它。

如果您认为链接列表不是正确的方式,请告诉我哪种方式会更好。

由于大多数答案实际上并未涉及问题的实质内容,仅仅是意图,这可能有助于:

据我所知,链接列表和循环链接列表之间的唯一区别是迭代器在到达列表的结尾或开头时的行为。 支持循环链表的行为的一种非常简单的方法是为LinkedListNode编写扩展方法,该方法返回列表中的下一个节点,如果不存在这样的节点,则返回第一个节点,类似地,用于检索前一个节点或最后一个节点。一个,如果没有这样的节点。 以下代码应该完成,虽然我还没有测试过:

static class CircularLinkedList { public static LinkedListNode NextOrFirst(this LinkedListNode current) { return current.Next ?? current.List.First; } public static LinkedListNode PreviousOrLast(this LinkedListNode current) { return current.Previous ?? current.List.Last; } } 

现在你可以调用myNode.NextOrFirst()而不是myNode.Next,你将拥有循环链表的所有行为。 您仍然可以执行常量时间删除,并在列表中的所有节点之前和之后插入等。 如果我遗失了循环链表中的其他一些关键位,请告诉我。

从BCL LinkedList类派生可能是个坏主意。 该类被设计为非循环列表。 试图使它循环只会导致你的问题。

你写自己的东西可能要好得多。

我不认为循环链表是联系人列表的正确数据结构。 一个简单的List <>或Collection <>就足够了。

您是否有特定要求使用循环链表(即家庭作业)? 如果没有,我建议使用简单的List类来存储您的联系人。

循环链接列表通常使用数组来实现,这使得它们非常快并且本质上不需要动态resize。 您只需要快速检查读取和写入索引以查看它们是否从最终落下,如果是,则将其重置为零(或者一个,无论如何)。

但是,它们通常用于输入缓冲区之类的东西,一旦读取数据就没有实际值。 联系人列表具有持久价值,一旦列表填满,新联系人将覆盖旧联系人,这可能没问题,除非你覆盖了你遗嘱中留下一堆现金的祖母。


我不认为链表是最有效的循环缓冲区(原始问题)。

循环缓冲区的目的是速度,并且在循环缓冲区的上下文中,数组根本不能用于速度。 即使您保留指向上次访问的链接列表项的指针,数组仍然会更有效。 列表具有循环缓冲区不需要的动态resizefunction(开销)。 话虽如此,我认为循环缓冲区可能不是您提到的应用程序(联系人列表)的正确结构。

 class CircularArray : IEnumerator { private readonly T[] array; private int index = -1; public T Current { get; private set; } public CircularArray(T[] array) { Current = default(T); this.array = array; } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { if (++index >= array.Length) index = 0; Current = array[index]; return true; } public void Reset() { index = -1; } public void Dispose() { } } 

基于模数的解决方案。

如果循环缓冲区实现为原始数组(或任何其他类型的集合,它的重要性)

 T[] array; 

我们将当前项的索引存储到int current_index ,我们可以按如下方式循环上下缓冲区:

 T NextOrFirst() { return array[(current_index + 1) % array.Length]; } T PreviousOrLast() { return array[(current_index + array.Length - 1) % array.Length]; } 

任何XAML绑定集合都可以使用相同的方法。

这个基于CList的循环列表怎么样。

我认为这个问题最正确的数据结构是一个循环的双向链表。 使用此数据结构,您可以在联系人列表中自由上下

 class Program { static void Main(string[] args) { int[] numbers = { 1, 2, 3, 4, 5, 6, 7 }; IEnumerable circularNumbers = numbers.AsCircular(); IEnumerable firstFourNumbers = circularNumbers.Take(4); // 1 2 3 4 IEnumerable nextSevenNumbersfromfourth = circularNumbers .Skip(4).Take(7); // 4 5 6 7 1 2 3 } } public static class CircularEnumerable { public static IEnumerable AsCircular(this IEnumerable source) { if (source == null) yield break; // be a gentleman IEnumerator enumerator = source.GetEnumerator(); iterateAllAndBackToStart: while (enumerator.MoveNext()) yield return enumerator.Current; enumerator.Reset(); if(!enumerator.MoveNext()) yield break; else yield return enumerator.Current; goto iterateAllAndBackToStart; } } 

如果你想要更进一步,做一个CircularList并保持相同的枚举器,以便在样本中旋转时跳过Skip()