在C#中创建循环链接列表?

在C#中创建循环链接列表?,c#,linked-list,addressbook,C#,Linked List,Addressbook,在C#中创建循环链接列表的最佳方法是什么。我应该从LinkedList集合中派生它吗?我计划用这个链表创建一个简单的通讯簿来存储我的联系人(这将是一个糟糕的通讯簿,但我不在乎,因为我是唯一使用它的人)。我主要只是想创建关键链接列表,以便在其他项目中再次使用它 如果您不认为链表是正确的方式,请告诉我哪种方式更好。我不认为循环链表是联系人列表的正确数据结构。一个简单的列表或集合就足够了。从BCL LinkedList类派生可能不是一个好主意。该类被设计为非循环列表。试图让它循环只会给你带来麻烦 你自

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


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

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

从BCL LinkedList类派生可能不是一个好主意。该类被设计为非循环列表。试图让它循环只会给你带来麻烦


你自己写可能会更好。

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

这样如何。

循环链接列表通常使用数组实现,这使得它们非常快速,而且本质上不需要动态调整大小。您只需要快速检查读和写索引,看看它们是否从末尾掉下来,如果是这样,请将其重置为零(或一,随便什么)

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


我不认为链表是获得循环缓冲区的最有效方式(最初的问题)

循环缓冲区的目的是提高速度,在循环缓冲区的环境中,数组的速度是无法与之相比的。即使保留指向上次访问的链表项的指针,数组仍然会更有效。列表具有循环缓冲区不需要的动态调整大小功能(开销)。
话虽如此,我认为循环缓冲区可能不是您提到的应用程序(联系人列表)的正确结构。

因为这些答案中的大多数实际上并没有触及问题的实质,只是意图,也许这将有助于:

就我所知,链表和循环链表之间的唯一区别是迭代器到达列表的末尾或开头时的行为。支持循环链表行为的一种非常简单的方法是为LinkedListNode编写一个扩展方法,该扩展方法返回列表中的下一个节点,如果不存在这样的节点,则返回第一个节点;同样,如果不存在这样的节点,则返回上一个节点或最后一个节点。下面的代码应该可以实现这一点,尽管我还没有对其进行测试:

static class CircularLinkedList {
    public static LinkedListNode<T> NextOrFirst<T>(this LinkedListNode<T> current)
    {
        return current.Next ?? current.List.First;
    }

    public static LinkedListNode<T> PreviousOrLast<T>(this LinkedListNode<T> current)
    {
        return current.Previous ?? current.List.Last;
    }
}
静态类循环链接列表{
公共静态LinkedListNode NextOrFirst(此LinkedListNode当前)
{
返回current.Next??current.List.First;
}
公共静态LinkedListNode PreviousOrLast(此LinkedListNode当前)
{
返回当前.Previous??当前.List.Last;
}
}

现在,您只需调用myNode.NextOrFirst()而不是myNode.Next,您将拥有循环链表的所有行为。您仍然可以在列表中的所有节点之前和之后执行固定时间删除和插入等操作。如果我缺少循环链表的其他关键点,请告诉我。

我认为解决此问题最正确的数据结构是循环双链表。使用此数据结构,您可以通过联系人列表自由上下移动
class CircularArray<T> : IEnumerator<T>
{
    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[]数组; 私有整数指数=-1; 公共T当前{get;私有集;} 公共循环数组(T[]数组) { 电流=默认值(T); this.array=数组; } 对象IEnumerator.Current { 获取{返回当前;} } 公共图书馆 { 如果(++索引>=array.Length) 指数=0; 当前=数组[索引]; 返回true; } 公共无效重置() { 指数=-1; } public void Dispose(){} }
课程计划
{
静态void Main(字符串[]参数)
{
int[]数字={1,2,3,4,5,6,7};
IEnumerable circular numbers=numbers.AsCircular();
IEnumerable FirstFourNumber=循环数
.拿(4);/1234
IEnumerable nextSevenNumbersfromfourth=循环数
.跳过(4).拿(7);//4 5 6 7 1 2 3
}
}
公共静态类循环数
{
公共静态IEnumerable AsCircular(此IEnumerable源)
{
if(source==null)
让步;做一个绅士
IEnumerator枚举器=source.GetEnumerator();
iterateAllAndBackToStart:
while(枚举数.MoveNext())
产生返回枚举数。当前;
枚举数。重置();
如果(!enumerator.MoveNext())
屈服断裂;
其他的
产生返回枚举数。当前;
转到iterateAllAndBackToStart;
}
}

如果您想更进一步,请制作一个
循环列表
,并按住相同的枚举数,以便在像示例中那样旋转时跳过
skip()

基于模的解决方案

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

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

T NextOrFirst()
{
返回数组[(当前_索引+1)%array.Length];
}
T PreviousOrLast()
{
返回数组[(当前_索引+array.Length-1)%array.Length];
}
同样的方法也适用于美国
class Program
{
    static void Main(string[] args)
    {
        int[] numbers = { 1, 2, 3, 4, 5, 6, 7 };

        IEnumerable<int> circularNumbers = numbers.AsCircular();

        IEnumerable<int> firstFourNumbers = circularNumbers
            .Take(4); // 1 2 3 4

        IEnumerable<int> nextSevenNumbersfromfourth = circularNumbers
            .Skip(4).Take(7); // 4 5 6 7 1 2 3 
    }
}

public static class CircularEnumerable
{
    public static IEnumerable<T> AsCircular<T>(this IEnumerable<T> source)
    {
        if (source == null)
            yield break; // be a gentleman

        IEnumerator<T> 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;
    }
}