c# - ordenar - Ordenando una lista enlazada
ordenar lista enlazada java (8)
La opción más simple es probablemente extraer los datos, ordenarlos en un mecanismo que ya admite clasificación (matrices, List<T>
o IEnumerable<T>
través de LINQ) y volver a compilar la lista vinculada con los datos ordenados.
Si desea escribir su propio algoritmo de ordenamiento, entonces puede encontrar Comparer<T>.Default
útil (suponiendo que esté usando genéricos). Esto debería permitirle comparar cualquier artículo que sea IComparable<T>
o IComparable
.
Como nota adicional, note que .NET ya incluye LinkedList<T>
etc; si esto es solo para aprender, etc., entonces bien ;-p
He escrito una clase de lista enlazada básica en C #. Tiene un objeto Node, que (obviamente) representa cada nodo en la lista.
El código no usa IEnumerable, sin embargo, ¿puedo implementar una función de clasificación? El lenguaje que estoy usando es C #. ¿Hay un ejemplo de esto en C #?
Estoy trabajando con esta muestra :
Gracias
Por supuesto, puede implementar una función de clasificación utilizando una lista de enlaces simples. Merge sort podría ser un algoritmo adecuado para probar, es bastante simple.
Quicksort funcional y Mergesort
Aquí hay una lista enlazada con los métodos quicksort y mergesort escritos en un estilo funcional:
class List
{
public int item;
public List rest;
public List(int item, List rest)
{
this.item = item;
this.rest = rest;
}
// helper methods for quicksort
public static List Append(List xs, List ys)
{
if (xs == null) return ys;
else return new List(xs.item, Append(xs.rest, ys));
}
public static List Filter(Func<int,bool> p, List xs)
{
if (xs == null) return null;
else if (p(xs.item)) return new List(xs.item, Filter(p, xs.rest));
else return Filter(p, xs.rest);
}
public static List QSort(List xs)
{
if (xs == null) return null;
else
{
int pivot = xs.item;
List less = QSort(Filter(x => x <= pivot, xs.rest));
List more = QSort(Filter(x => x > pivot, xs.rest));
return Append(less, new List(pivot, more));
}
}
// Helper methods for mergesort
public static int Length(List xs)
{
if (xs == null) return 0;
else return 1 + Length(xs.rest);
}
public static List Take(int n, List xs)
{
if (n == 0) return null;
else return new List(xs.item, Take(n - 1, xs.rest));
}
public static List Drop(int n, List xs)
{
if (n == 0) return xs;
else return Drop(n - 1, xs.rest);
}
public static List Merge(List xs, List ys)
{
if (xs == null) return ys;
else if (ys == null) return xs;
else if (xs.item <= ys.item) return new List(xs.item, Merge(xs.rest, ys));
else return new List(ys.item, Merge(xs, ys.rest));
}
public static List MSort(List xs)
{
if (Length(xs) <= 1) return xs;
else
{
int len = Length(xs) / 2;
List left = MSort(Take(len, xs));
List right = MSort(Drop(len, xs));
return Merge(left, right);
}
}
public static string Show(List xs)
{
if(xs == null) return "";
else return xs.item.ToString() + " " + Show(xs.rest);
}
}
Heapsort funcional usando un montón de emparejamiento
Bonificación: heapsort (usando el montón de emparejamiento funcional).
class List
{
// ...
public static Heap List2Heap(List xs)
{
if (xs == null) return null;
else return Heap.Merge(new Heap(null, xs.item, null), List2Heap(xs.rest));
}
public static List HSort(List xs)
{
return Heap.Heap2List(List2Heap(xs));
}
}
class Heap
{
Heap left;
int min;
Heap right;
public Heap(Heap left, int min, Heap right)
{
this.left = left;
this.min = min;
this.right = right;
}
public static Heap Merge(Heap a, Heap b)
{
if (a == null) return b;
if (b == null) return a;
Heap smaller = a.min <= b.min ? a : b;
Heap larger = a.min <= b.min ? b : a;
return new Heap(smaller.left, smaller.min, Merge(smaller.right, larger));
}
public static Heap DeleteMin(Heap a)
{
return Merge(a.left, a.right);
}
public static List Heap2List(Heap a)
{
if (a == null) return null;
else return new List(a.min, Heap2List(DeleteMin(a)));
}
}
Para el uso real, desea volver a escribir los métodos de ayuda sin utilizar la recursión, y tal vez usar una lista mutable como la incorporada.
Cómo utilizar:
List xs = new List(4, new List(2, new List(3, new List(1, null))));
Console.WriteLine(List.Show(List.QSort(xs)));
Console.WriteLine(List.Show(List.MSort(xs)));
Console.WriteLine(List.Show(List.HSort(xs)));
Imperativo en el lugar Quicksort para listas vinculadas
Se solicitó una versión en contexto. Aquí hay una implementación muy rápida. Escribí este código de arriba a abajo sin buscar oportunidades para mejorar el código, es decir, cada línea es la primera línea que me vino a la mente. Es extremadamente feo porque utilicé nulo como la lista vacía :) La sangría es inconsistente, etc.
Además, probé este código solo en un ejemplo:
MList ys = new MList(4, new MList(2, new MList(3, new MList(1, null))));
MList.QSortInPlace(ref ys);
Console.WriteLine(MList.Show(ys));
¡Mágicamente funcionó la primera vez! Sin embargo, estoy bastante seguro de que este código contiene errores. No me hagas responsable
class MList
{
public int item;
public MList rest;
public MList(int item, MList rest)
{
this.item = item;
this.rest = rest;
}
public static void QSortInPlace(ref MList xs)
{
if (xs == null) return;
int pivot = xs.item;
MList pivotNode = xs;
xs = xs.rest;
pivotNode.rest = null;
// partition the list into two parts
MList smaller = null; // items smaller than pivot
MList larger = null; // items larger than pivot
while (xs != null)
{
var rest = xs.rest;
if (xs.item < pivot) {
xs.rest = smaller;
smaller = xs;
} else {
xs.rest = larger;
larger = xs;
}
xs = rest;
}
// sort the smaller and larger lists
QSortInPlace(ref smaller);
QSortInPlace(ref larger);
// append smaller + [pivot] + larger
AppendInPlace(ref pivotNode, larger);
AppendInPlace(ref smaller, pivotNode);
xs = smaller;
}
public static void AppendInPlace(ref MList xs, MList ys)
{
if(xs == null){
xs = ys;
return;
}
// find the last node in xs
MList last = xs;
while (last.rest != null)
{
last = last.rest;
}
last.rest = ys;
}
public static string Show(MList xs)
{
if (xs == null) return "";
else return xs.item.ToString() + " " + Show(xs.rest);
}
}
Esta podría no ser la mejor solución, pero es tan simple como puedo pensar. Si alguien puede pensar en algo más simple pero aún rápido, me encantaría escucharlo.
LO SIENTO QUE es C ++, debería traducirse.
List * SortList(List * p_list)
{
if(p_list == NULL || p_list->next == NULL)
return p_list;
List left, right;
List * piviot = p_list;
List * piviotEnd = piviot;
List * next = p_list->next;
do
{
p_list = next;
next = next->next;
//FIGURE OUT WHICH SIDE I''M ADDING TO.
if(p_list->data > piviot->data )
right.InsertNode(p_list);
else if(p_list->data < piviot->data)
left.InsertNode(p_list);
else
{ //we put this in it''s own list because it doesn''t need to be sorted
piviotEnd->next = p_list;
piviotEnd= p_list;
}
}while(next);
//now left contains values < piviot and more contains all the values more
left.next = SortList(left.next);
right.next = SortList(right.next);
//add the piviot to the list then add the rigth list to the full list
left.GetTail()->next = piviot;
piviotEnd->next = right.next;
return left.next;
}
for(int i=0; i<counter;i++)
{
while(current.next!=null)
{
if(current.elemen>current.next.element)
{
Swap(current.elment,current.next.element);
}
current=current.next;
}
}
incrementar el contador cuando agrega o inserta elementos en sus listas vinculadas
Si desea realmente utilizar el hecho de que está utilizando una lista vinculada, en lugar de trabajar en torno a ella, le sugiero ordenar por inserción.
Normalmente, una ordenación de inserción no es muy eficiente - O(n^2)
en el peor de los casos, pero con la lista vinculada esto se puede mejorar a O(n log n)
seudo:
for i in range (1,n):
item = arr[i]
location = binary_search(l=root, r=i, value=item.val) // O(log i)
insert_item_before(arr[location], item) // O(1)
En el algoritmo regular, la parte insertada toma O(i)
porque es posible que tengamos que cambiar todos los elementos que son más grandes que el item
. porque una lista vinculada nos permite hacer la inserción sin desplazamiento, podemos buscar la ubicación con una búsqueda binaria y, por lo tanto, la parte de inserción solo toma O(log i)
Nota: generalmente una ordenación de inserción tiene un rendimiento O(n)
en el mejor de los casos (si la matriz está ordenada). Lamentablemente, este no es el caso aquí porque la búsqueda binaria toma siempre O(log n)
pasos.
public LinkedListNode<int> Sort2(LinkedListNode<int> head, int count)
{
var cur = head;
var prev = cur;
var min = cur;
var minprev = min;
LinkedListNode<int> newHead = null;
LinkedListNode<int> newTail = newHead;
for (int i = 0; i < count; i++)
{
cur = head;
min = cur;
minprev = min;
while (cur != null)
{
if (cur.Value < min.Value)
{
min = cur;
minprev = prev;
}
prev = cur;
cur = cur.Next;
}
if (min == head)
head = head.Next;
else if (min.Next == null)
minprev.Next = null;
else
minprev.Next = minprev.Next.Next;
if (newHead != null)
{
newTail.Next = min;
newTail = newTail.Next;
}
else
{
newHead = min;
newTail = newHead;
}
}
return newHead;
}
Algunas personas (incluyéndome a mí) pueden haber querido clasificar LinkedList<T>
de la biblioteca .net.
La forma más fácil es usar Linq, ordenar y, finalmente, crear una nueva lista vinculada. pero esto crea basura. para colecciones pequeñas no sería un problema, pero para colecciones grandes puede no ser tan eficiente.
para las personas que desean un cierto grado de optimización, aquí hay una implementación genérica de ordenamiento rápido in situ para la lista enlazada doble de .net.
esta implementación no se divide / combina, sino que comprueba los nodos para conocer los límites de cada recursión.
/// <summary>
/// in place linked list sort using quick sort.
/// </summary>
public static void QuickSort<T>(this LinkedList<T> linkedList, IComparer<T> comparer)
{
if (linkedList == null || linkedList.Count <= 1) return; // there is nothing to sort
SortImpl(linkedList.First, linkedList.Last, comparer);
}
private static void SortImpl<T>(LinkedListNode<T> head, LinkedListNode<T> tail, IComparer<T> comparer)
{
if (head == tail) return; // there is nothing to sort
void Swap(LinkedListNode<T> a, LinkedListNode<T> b)
{
var tmp = a.Value;
a.Value = b.Value;
b.Value = tmp;
}
var pivot = tail;
var node = head;
while (node.Next != pivot)
{
if (comparer.Compare(node.Value, pivot.Value) > 0)
{
Swap(pivot, pivot.Previous);
Swap(node, pivot);
pivot = pivot.Previous; // move pivot backward
}
else node = node.Next; // move node forward
}
if (comparer.Compare(node.Value, pivot.Value) > 0)
{
Swap(node, pivot);
pivot = node;
}
// pivot location is found, now sort nodes below and above pivot.
// if head or tail is equal to pivot we reached boundaries and we should stop recursion.
if (head != pivot) SortImpl(head, pivot.Previous, comparer);
if (tail != pivot) SortImpl(pivot.Next, tail, comparer);
}