繁体   English   中英

在 C# 中创建循环链表?

[英]Creating a circularly linked list in C#?

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

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

由于这些答案中的大多数实际上并没有触及问题的实质,仅仅是意图,也许这会有所帮助:

据我所知,链表和循环链表之间的唯一区别是迭代器到达列表末尾或开头时的行为。 支持循环链表行为的一个非常简单的方法是为 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;
    }
}

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

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

你可能最好自己写。

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

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

循环链表通常使用数组来实现,这使得它们非常快,并且本质上不需要动态调整大小。 您只需要快速检查读取和写入索引,看看它们是否从末尾脱落,如果是,请将其重置为零(或一,无论如何)。

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


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

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

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[] 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<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;
    }
}

如果您想更进一步,请制作一个CircularList并保持相同的枚举数以在像示例中一样旋转时跳过Skip()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM