2010-07-23 14 views
9

¿Cómo clasificaría una sola lista vinculada? (el problema aquí es la propiedad individual + utilizando LinkedList para la clasificación es más difícil que una matriz) tuve gustaría ver un pseudo código ..Ordene una sola lista vinculada

tratar de hacerlo lo más eficiente posible de tiempo y espacio.

Gracias!

+0

tarea? Si es así, indique qué tan lejos ha llegado hasta el momento. –

+1

posible duplicado de [Ordenando una lista vinculada] (http://stackoverflow.com/questions/768095/sorting-a-linked-list) – kennytm

Respuesta

7

Mergesorting involucra a pocos pasos simples:

  1. Comprobar si la lista se vacío o tiene un solo elemento. Si es así, devuelva la lista sin cambios.

  2. Divida la lista por la mitad. Mergesort ambas partes.

  3. Combine las listas sacando repetidamente el elemento más pequeño de ambas listas.Dado que las listas de piezas ya están clasificadas, solo se trata de mirar los primeros elementos en ambas listas y elegir el más pequeño.

  4. Regresar la lista fusionada.

Como resultado, obtendrá una lista vinculada ordenada en orden de menor elemento primero.

Ejemplo de código en Haskell:

import Data.List(splitAt) 

--Mergesorts a list by smallest element first. 
sort :: Ord a => [a] -> [a] 
sort = sortBy (<) 

--Generic sort that can sort in any order. 
sortBy :: (a -> a -> Bool) -> [a] -> [a] 
sortBy _ [] = [] 
sortBy _ [x] = [x] 
sortBy f xs = merge f (sortBy f first) (sortBy f second) 
    where 
     (first,second) = split xs 

--Splits a list in half. 
split :: [a] -> ([a],[a]) 
split xs = splitAt (halfLength xs) xs 

--Returns a lists length divided by two as a whole number (rounded). 
halfLength :: [a] -> Int 
halfLength = round . (/2) . fromIntegral . length 

--Merges two lists in the provided order. 
merge :: (a -> a -> Bool) -> [a] -> [a] -> [a] 
merge _ [] [] = [] 
merge _ [] (y:ys) = y:ys 
merge _ (x:xs) [] = x:xs 
merge f (x:xs) (y:ys) = 
    if f x y 
     then x : merge f xs (y:ys) 
     else y : merge f (x:xs) ys 
+0

Creo que esta implementación de mergesort usará más que espacio constante. Permite tomar una lista de 64 términos. Si dividí la lista en 2 sublistas, tengo que recordar dónde está la ubicación en memoria de sus cabezas. Primero me dividí una vez y recuerdo las indicaciones 1ra y 33a. Luego dividí la primera mitad nuevamente, y tengo que recordar las indicaciones 1ra, 17ma y 33ra. A medida que aumenta el número de términos, también aumenta la cantidad de nodos de cabeza que necesito recordar. Le expliqué cómo hacer un mergesort en contexto [aquí] (http://stackoverflow.com/questions/3315936/sort-a-single-linked-list/3322097#3322097). –

0

El tipo de inserción y el QuickSort se pueden realizar en una lista de enlace único con la misma eficacia que en un conjunto.

+1

Gracias por la respuesta rápida, ¿puede explicar cómo? Parece que esos géneros utilizan la propiedad de acceso aleatorio para lograr la eficacia p. en tipo de fusión, ¿cómo accedería al centro de la lista? debe ejecutar n/2 pasos –

+0

Quicksort no se puede hacer en una lista vinculada individualmente con la misma eficacia que en una matriz. – Cam

+0

@incrediman: ¿Por qué no? Seleccione el primero de la lista como pivote, luego repita el resto y cree dos listas nuevas. Ordene estas dos listas. Empaléelos juntos. En realidad es más fácil con las listas enlazadas que con las matrices. (Admito que estaba equivocado sobre mergesort) –

5

Dado que una lista vinculada es simplemente una serie de elementos señalados por otros elementos, puede construir una matriz de punteros con O (n) tiempo y O (n) espacio, ordenarlos utilizando cualquiera de los excelentes algoritmos de clasificación con O (n log n) tiempo y O (1) espacio, luego reconstruye la lista vinculada desde cero con O (n) tiempo y O (1) espacio.

En general, ese es el tiempo O (n log n) y el espacio O (n).

+0

suena genial, ¿es posible ordenarlo usando O (1) espacio y O (nlogn) tiempo? –

+2

No, no que yo sepa. El hecho de que no pueda acceder a los nodos de lista arbitrarios en O (1) lo hace poco probable. De hecho, es el espacio O (n) el que permite el O (1) tiempo de acceso individual que a su vez permite un O (n log n) tiempo de ordenamiento global. – paxdiablo

2

Creo que puede hacer esto con una ordenación rápida in situ.
Estaba equivocado. Esto no funciona con una lista vinculada individualmente, ya que requiere poder dar un paso atrás en la lista.

Así que la verdadera pregunta es cómo hacer una clasificación rápida en el lugar.

Aquí vamos ...

1) Tome un puntero la primera, segunda y el último término de la lista enlazada,.
2) Paso del segundo puntero a través de la lista hasta que llegue a un término que es más grande que el primer término.
3) Pasa el tercer puntero hacia atrás en la lista hasta que toques un término que sea más pequeño que el primer término. Este paso no funciona con una lista vinculada individualmente.
4) Cambie los valores del segundo y tercer punteros.
5) Repita los pasos 2) a 5) hasta que el segundo y el tercer puntero se igualen.
6) Insertar el primer término después de la segunda puntero

-En este punto, la lista enlazada se divide en:
[términos menor que x] x [términos mayor que x]

7 Repita los pasos 2) a 7) para los [términos menores que x] y los [términos mayores que x] hasta que el tamaño del bloque [términos ________ que x] sea uno.

Espacio: 3 punteros por capa.
O (log (n))

Tiempo: Igual que el rápido Ordenado
O (n log (n)) en general
O (n * n) en el peor de los casos (si la lista es o bien ya ordenados o en orden inverso)


Editado para el formato y la estupidez

+0

Me encantó leer esto, y creo que el algoritmo es sólido después de una breve mirada. Sin embargo, no es, creo, O (1) espacio. Creo que es el espacio O (log n). Recuerde que debe tener 3 punteros * por cada * "marco de pila" recursivo (incluso si no usa recursión real). No puedes abandonar su antiguo valor al dividir y conquistar. –

+0

Descrito aquí: http://en.wikipedia.org/wiki/Inplace_algorithm. * Quicksort se describe comúnmente como un algoritmo in situ, pero en realidad no es uno. La mayoría de las implementaciones requieren espacio O (log n) para soportar su división y conquistar la recursión. * Aún mejor que O (n), aunque sí +1. –

+0

@Mark Peters - Ah, tienes razón. No pensé en los punteros en el marco de la pila, lo cual obviamente es una consideración necesaria dado que es pseudo recursivo. Mi error. Cruzaré mi cabeza un poco más por algún algoritmo de clasificación en el lugar que pueda funcionar en O (n log (n)). –

6

he estado pensando en esto un poco más, y creo que se logre el o (n log (n) el tiempo) y O (1) condición espacial con Merge ordenar.

Veamos ...
Tome la lista:
3 -> 2 -> 1 -> 5 -> 6 -> 4

Primer paso:
Establecer un puntero para el primero, segundo término y 3er términos
Establezca el término más pequeño entre el 1er y el segundo puntero para señalar el término más grande.
Establezca el último de los 2 términos para que apunte al resto de la lista original.
Repita hasta el final de la lista.
2 -> 3 -> 1 -> 5 -> 4 -> 6

En este punto, cada par de términos está ordenado.

pase enésimo:
Establecer un puntero a la primera, (2^(N-1)) -ésimo, y (2^(n)) + 1 th términos
Tome el nodo valorado más pequeño e incrementar su puntero .
Repita el proceso hasta que se agoten ambas listas (de longitud 2^N), añadiendo el nodo valorado más pequeño cada vez al nodo valorado más pequeño anterior.
Establezca el puntero al resto de la lista original.
Repita hasta el final de la lista.

pase 0 ª: 3 -> 2 -> 1 -> 5 -> 6 -> 4 (cada bloque de 1 plazo se ordena) (trivial)
primero pase: 2 -> 3 -> 1 -> 5 -> 4 -> 6 (se ordena cada bloque de 2 términos)
2º paso: 1 -> 2 -> 3 -> 5 -> 4 -> 6 (se ordena cada bloque de 4 términos)
3er paso: 1 -> 2 -> 3 -> 4 -> 5 -> 6 (se ordena cada bloque de 8 términos)

Tiempo: log (n) pasa, con n comparaciones para cada pase.
O (n log (n))

espacio: las variables de puntero y enteros
O (1)

Cuestiones relacionadas