¿Creando una lista con enlaces circulares en C #?

Cuál sería la mejor manera de crear una lista vinculada circularmente en C #. ¿Debo derivarlo de la colección LinkedList ? Estoy planeando crear una libreta de direcciones simple usando esta lista vinculada para almacenar mis contactos (va a ser una libreta de apegos, pero no me importa porque seré el único en usarla). Principalmente, solo quiero crear la lista crucialmente vinculada para que pueda usarla de nuevo en otros proyectos.

Si no crees que la Lista enlazada es la forma correcta de hacerlo, házmelo saber qué camino sería mejor.

Como la mayoría de estas respuestas no llegan a la esencia de la pregunta, simplemente la intención, tal vez esto ayude:

Hasta donde puedo decir, la única diferencia entre una Lista Vinculada y una Lista Vinculada Circular es el comportamiento de los iteradores al llegar al final o al comienzo de una lista. Una manera muy fácil de admitir el comportamiento de una lista vinculada circular es escribir un método de extensión para un LinkedListNode que devuelve el siguiente nodo en la lista o el primero si no existe ese nodo, y de manera similar para recuperar el nodo anterior o el último uno si no existe tal nodo. El siguiente código debería lograr eso, aunque no lo he probado:

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

Ahora puede simplemente llamar a myNode.NextOrFirst () en lugar de myNode.Next y tendrá todo el comportamiento de una lista circular vinculada. Todavía puede hacer extracciones de tiempo constante e insertar antes y después de todos los nodos en la lista y similares. Si falta alguna otra parte clave de una lista circular vinculada, no me la digas.

Probablemente sería una mala idea derivar de la clase BCL LinkedList. Esa clase está diseñada para ser una lista no circular. Tratar de hacerlo circular solo te causará problemas.

Probablemente estés mucho mejor escribiendo el tuyo.

No creo que una lista circular vinculada sea la estructura de datos correcta para una lista de contactos. Una simple Lista <> o Colección <> debería ser suficiente.

¿Tiene un requisito específico para usar una lista con enlaces circulares (es decir, deberes)? De lo contrario, sugeriría utilizar la simple clase List para almacenar sus contactos.

Las listas de enlaces circulares a menudo se implementan usando arreglos que los hacen muy rápidos y, por su naturaleza, no requieren un cambio de tamaño dynamic. Solo necesita una comprobación rápida de los índices de lectura y escritura para ver si cayeron al final y, de ser así, restablecerlo a cero (o uno, lo que sea).

Sin embargo, generalmente se usan para cosas como búferes de entrada, donde los datos no tienen valor real una vez leídos. Las listas de contactos tienen un valor duradero y los contactos nuevos sobrescribirán a los contactos más antiguos una vez que la lista se llena, lo que podría estar bien a menos que sobrescriba a su abuela, que le está dejando un montón de dinero en efectivo en su testamento.


No creo que una lista vinculada sea la forma más eficiente de usar un buffer circular (la pregunta original).

El propósito de un búfer circular es la velocidad y un conjunto simplemente no se puede batir por la velocidad en el contexto de un búfer circular. Incluso si mantiene un puntero al último elemento de la lista vinculada a la que accedió, una matriz seguirá siendo más eficiente. Las listas tienen capacidades dinámicas de redimensionamiento (sobrecarga) que no son necesarias para los almacenamientos intermedios circulares. Habiendo dicho eso, creo que un buffer circular probablemente no sea la estructura correcta para la aplicación (lista de contactos) que mencionas.

 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() { } } 

Una solución basada en el módulo.

Si el búfer circular se implementa como una matriz en bruto (o cualquier otro tipo de colección para lo que importa)

 T[] array; 

y almacenamos en int current_index el índice del elemento actual, podemos desplazarnos hacia arriba y hacia abajo en el búfer de la siguiente manera:

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

El mismo enfoque se puede usar con cualquier colección de enlaces XAML.

¿Qué tal esta lista circular basada en CList ?

Creo que la estructura de datos más correcta para este problema es una lista circular doblemente vinculada. Con esta estructura de datos puede subir y bajar libremente a través de la lista de contactos

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

Si quiere ir más allá, haga una CircularList y sostenga el mismo enumerador para omitir el salto Skip() al rotar como en su muestra.