Algoritmos de Ordenamiento

Download Report

Transcript Algoritmos de Ordenamiento

Estructura de Datos En C++
Dr. Romeo Sánchez Nigenda.
E-mail: [email protected]
http://yalma.fime.uanl.mx/~romeo/
Oficina: 1er. Piso del CIDET. Oficina con Dr. Oscar Chacón
Horas de Tutoría: 10am-11am Martes y Jueves,
3:30pm-4:30pm Miércoles, 2:00pm-4:00pm Viernes.
Website: http://yalma.fime.uanl.mx/~romeo/ED/2011/
Sesiones: 48
Objetivo General: Conocerá y manejará las
estructuras internas de información
Temario:
1.
2.
3.
4.
5.
6.
7.
8.
9.
Conceptos Básicos
La Pila
40% Tareas
Colas
30% Examen Parcial
Recursión
30% Examen Final
Listas
10% Participación
Árboles
Ordenamiento
Búsqueda
Administración de Almacenamiento
Total a calificar: 110 puntos.
Material de apoyo:
Estructura de Datos con C y C++.
Yedidyah Langsam, Moshe J. Augenstein, Aaron M. Tenenbaum, Brooklyn College
Segunda Edición, Prentice-Hall.
Algorithms. Third Edition.
Parts 1-4, Fundamentals Data Structures Sorting Searching
Robert Sedgewick.
Estructura de Datos.
Román Martínez, Elda Quiroga.
Thomson Learning.
Cualquier libro de Estructura de Datos!
Software:
Compiladores GCC (GNU Compiler Collection)
IDEs (Integrated Development Environment):
http://www.eclipse.org/downloads/
http://kdevelop.org/
http://www.bloodshed.net/devcpp.html
7. Ordenamiento

Objetivo: El alumno aprenderá los métodos de ordenación
interna y externa más importantes actualmente, así como
su eficiencia.

Temario:
◦
◦
◦
◦
◦
◦
Antecedentes generales
Ordenación por intercambio directo (Bubble-sort)
Ordenación por inserción directa (Insertion-sort)
Ordenación por el método Shell
Ordenación por el método Quicksort
Ordenación por intercalación (Merge-sort)
Ordenamiento

El proceso de búsqueda se simplifica cuando los datos a considerar se
encuentran ordenados

Un archivo de tamaño n es una secuencia de n elementos r[0], r[1], …, r[n-1].
Cada elemento es un registro. A cada registro r[i] se le asocia una llave k[i].

Se dice que el archivo se encuentra ordenado por llave si i<j implica que k[i]
precede a k[j].
◦ Ejemplo: El archivo es el directorio telefónico. Cada entrada en el directorio es un
registro. La llave para ordenar es el campo de nombre del registro.

El proceso de ordenamiento puede ocurrir sobre los datos mismos, o sobre
apuntadores a los datos (ordenamiento por dirección), esto se realiza
cuando resulta muy costoso mover los datos mismos por su cantidad.
R
Llave
e
g
4
i
2
s
t
1
r
3
o
s
Campo
Llave
Campo
DDD
1
BBB
apuntadores
Llave
Campo
AAA
4
DDD
2
BBB
2
BBB
AAA
3
CCC
1
AAA
CCC
4
DDD
3
CCC
archivo ordenado
apuntadores
ordenados
Ordenamiento: Eficiencia

Consideraciones de eficiencia:
◦ Tiempo para codificar el programa de
ordenamiento
◦ Cantidad de tiempo máquina para ejecutar el
programa
◦ Cantidad de espacio necesaria para el programa.

Esperaríamos encontrar un ordenamiento
óptimo en O(n), sin tomar en cuenta el
contenido u orden de ingresos, pero la
mayoría de los métodos tienen requisitos de
tiempo entre O(n log n) a O(n2).
Ordenamiento de Burbuja: Bubble-sort

Se asume que x es un arreglo de enteros, del
cual se van a ordenar n elementos, de modo
que x[i] <= x[j], para 0<=i<j<n

Idea:
◦ Recorrer el archivo secuencialmente varias veces
◦ En cada iteración se compara cada elemento del
archivo con su sucesor x[i] con x[i+1]
◦ Se intercambian los elementos (swap) si no están
en el orden correcto
◦ Se llama ordenamiento por burbuja porque cada
valor lentamente asciende como una burbuja a su
posición correcta
EJEMPLO:
X
15
10
20
11
16
18
pass
15
10
20
11
16
18
0
[0]
[1]
10
15
20
11
16
18
[1]
[2]
15
20
11
16
18
[2]
[3]
11
20
16
18
[3]
[4]
16
20
18
[4]
[5]
18
20
10
10
10
10
15
15
15
n=6
swap
11
11
16
swap
swap
swap
Algoritmo Buble-sort
Detecta si hubo intercambios
en una pasada o no.
void bubble(int x[], int n){
int temp, j, pass;
int switched = TRUE;
for(pass = 0; pass<n-1&&switched;pass++){
switched = FALSE;
for (j=0; j<n-pass-1; j++)
{
if(x[j]>x[j+1]){
Los elementos que ya se
ordenaron no es necesario checarlos
switched = TRUE;
temp = x[j];
x[j] = x[j+1];
x[j+1] = temp;
}
}
}
Intercambio!
}
Eficiencia: El método en general es O(n2), ya que tiene (n-1) pasadas y (n-1)
comparaciones en cada pasada, en total n2-2n+1 comparaciones.
Ordenamiento por Selección Directa
Un ordenamiento por selección es aquel
en el que se seleccionan elemento sucesivos
en orden y se colocan en sus posiciones
correctas
 Idea:

◦ En un principio el algoritmo toma un arreglo no
ordenado
◦ En cada iteración se selecciona el elemento más
grande (o el menor) de los elementos restantes
del arreglo
◦ El elemento seleccionado se va apilando al
principio o al final del arreglo, intercambiando
posiciones con el elemento desordenado
EJEMPLO:
X
15
min
I
10
15
10
20
11
16
18
20
11
16
18
J
J
min
J
J
I
10
k
10
10
15
min
I
15
15
20
J
11
16
18
11
min
16
18
J
20
20
11
J
J
16
18
16
18
min
I
10
11
20
J
15
n=6
Algoritmo Selección Directa
Asume que el índice actual
void selectionSort(int x[], int n){ como el índice mínimo
int i, j, minindex;
for(i=0; i<n-1; i++){
minindex = i;
Actualiza el índice mínimo
for (j=i+1; j<n; j++)
si encuentras otro valor menor
{
if(x[j]<x[minindex]){
minindex = j;
}
}
int temp = x[i];
x[i] = x[minindex];
x[minindex] = temp;
}
}
Intercambio!
Ordenamiento por Inserción: Insertion-sort
Este método ordena un conjunto de registros
insertándolos en un archivo ordenado existente.
 Idea:

◦ Inicialmente, se utiliza el primer elemento del arreglo
como el componente que se encuentra ordenado
◦ Cuando ya tenemos k elementos ordenados, se toma
el elemento k+1, y se compara con los elementos
ordenados
◦ Se desplazan todos los elementos de 0 a k que sean
mayores a k+1
◦ Se inserta el elemento k+1 inmediatamente después
de algún elemento que no se deba desplazar.
EJEMPLO:
X
15
Elementos Ordenados
insertó al
principio
10
20
11
16
18
k
n=6
A insertar
10
15
10
20
11
16
18
10
15
20
11
16
18
11
16
18
20
11
k
No se
insertó
10
15
20
k
10
15
20
11
16
18
10
15
20
20
16
18
15
20
16
18
15
20
16
18
11
10
15
11
Se inserta
entre 10 y 15
10
11
Algoritmo Insertion-sort
void insertionSort(int x[], int n){
Los elementos menores de K
int i, k, y;
se asumen ordenados
for(k=1; k<n; k++){
Elemento a insertar
y = x[k];
for(i=k-1; i>=0 && y<x[i]; i--){
x[i+1] = x[i];
}
Desplazamiento
x[i+1] = y;
}
}
Inserción!
Eficiencia: El método en el peor caso es O(n2): (n-1) + (n-2) + 3 + 2 + 1 = (n-1) * n/2.
Ordenamiento de Shell
Método de ordenamiento de incremento decreciente.
 Idea:
◦ Mejorar el ordenamiento por inserción considerando elementos separados
por varias espacios en el archivo original. Esto lo hace considerando
subarchivos.
◦ La idea es utilizar el k-ésimo elemento para producir k subarchivos con k
espacios.
◦ Después de ordenar los primeros k subarchivos, se elige un valor más
pequeño de k y el archivo se divide en nuevos grupos.
◦ El proceso se repite hasta que k llega a ser 1. Con lo que se ordena todo el
subarchivo que viene siendo el archivo completo, utilizando el ordenamiento
por inserción.
◦ La idea es incrementar la velocidad del ordenamiento por inserción al
subdividir el archivo original en subarchivos, evitando realizar demasiados
desplazamientos al mover elementos entre espacios más grandes.
◦ Los valores para k, es decir la secuencia de espacios, en el algoritmo original
se determinaba dividiendo el número de elementos N del archivo entre 2, y
así sucesivamente hasta alcanzar 1. Existen otras caracterizaciones de la
secuencia de espacios que afectan el desempeño general del algoritmo.

EJEMPLO:
kespacios = {3,1}
15
10
20
k
space =3
space =1
11
16
n=6
18
j
20
11
y
16
11
15
10
18
11
k … k
10
20
k
11
j
10
18
15
16
20
10
10
k
11
j
18
15
16
20
18
10
11
k
18
j
15
16
20
15
10
k
11
18
j
18
16
20
…
15
16
j
y
y
18
16
18
y
15
Algoritmo de Shell
void shellSort(int x[], int n, int spaces[], int lengthspaces){
int i, j, k, space, y;
for(i=0;i<lengthspaces; i++)
Elemento para inserción
{
space = spaces[i];
Secuencia
de espacios
for(j=space; j<n; j++){
y = x[j];
for (k = j-space; k>=0 && y<x[k]; k-=space){
Tamaño del
espacio
x[k+space] = x[k];
}
x[k+space] = y;
Desplazamiento
}
}
}
Inserción!
La implementación original del algoritmo requiere O(n2) comparaciones e
intercambios en el peor caso.
Ordenamiento Quicksort


Método de ordenamiento basado en la técnica de divide y vencerás.
Idea:
◦ Elegir un elemento de la lista x a ordenar al que se le denomina pivote.
◦ Coloque el elemento pivote en la posición j de tal manera que prevalezcan las
condiciones siguientes:


Cada uno de los elementos en las posiciones 0 a j-1 es menor que o igual al pivote
Cada uno de los elementos en las posiciones j+1 a n-1 es mayor que o igual al pivote
◦ Bajo estas condiciones, el elemento x[j] es el j-ésimo elemento más pequeño de la
lista
X
0
…
J-1
J
J+1
…
N-1
pivote
◦ Se repite el proceso anterior con los subarreglos, note que el pivote ya se
encuentra en la posición correcta j:



x[0] a x[j-1] y x[j+1] a x[n-1]
Permite en promedio ordenar n elementos en un tiempo proporcional a n log n en el
mejor caso (pivote en el centro de la lista), el peor caso es n2 (cuando el pivote se
encuentra en un extremo de la lista)
La elección del pivote constituye una de las principales mejoras del algoritmo, se
puede elegir a ciegas, el primero o el último, un punto intermedio, por reposición,
etc.
Ordenamiento Quicksort: Selección del Pivote

Por reposicionamiento: Se utilizan dos índices, up y down, se establece como
valor del pivote el primer elemento del arreglo por ejemplo.

Los dos apuntadores up y down recorren la lista simultáneamente con down por
la izquierda y up por la derecha uno hacia el otro de la forma siguiente:
◦ Aumentar el apuntador down en una posición hasta que X[down] > pivote
◦ Decrementar el apuntador up en una posición hasta que X[up] <= pivote
◦ Si up > down y las dos condiciones anteriores se cumplen, se intercambian X[down] con X[up]
◦ El proceso se repite hasta que los apuntadores se cruzan (up<=down), en cuyo punto x[up] se
intercambia con x[pivote], y se retorna up como el pivote.
15
10
pivote
down
15
10
pivote
15
10
10
15
pivote
11
20
11
n=6
11
15
pivote
16
18
11
16
18
20
16
18
20
16
18
16
18
up
11
up
10
18
up
20
down
10
16
up
down
pivote
Se rompe el ciclo y
se intercambia up
como el nuevo
pivote.
11
down
pivote
15
20
up
down
20
Recursivamente se ordenan las sublistas,
antes y después del pivote
Algoritmo Quicksort
int particion (int * x, int izq, int der){
int pivote, down, up, temp;
down = izq;
up = der;
pivote = x[izq];
while (down < up){
while(x[down]<=pivote && down<der)
down++;
while(x[up]>pivote)
up--;
void Quicksort(int * x int lb, int ub) {
if(down < up){
int pivote;
temp = x[down];
if(lb < ub){
pivote=particion(x, lb, ub);
x[down] = x[up];
Quicksort(x, lb, pivote-1);
x[up] = temp;
Quicksort(x, pivote+1, ub);
}
}
}
}
x[izq] = x[up];
x[up] = pivote;
return up;
}
Ordenamiento por intercalación: Merge-sort

Método de ordenamiento basado en técnica de comparaciones.

Idea:
◦ Si el arreglo es de longitud 0 o 1, entonces se encuentra ordenado. De otra manera,
◦ Dividir el arreglo desordenado en dos subarreglos de tamaño proporcional a la mitad
◦ Ordenar cada subarreglo recursivamente reaplicando el método merge-sort
◦ Finalmente, intercalar (merge) los dos subarreglos en un arreglo ordenado

La idea de intercalación asume que es más fácil ordenar una lista pequeña, y que
menos pasos se necesitan para construir una lista ordenada de dos listas
ordenadas que de dos listas desordenadas.
Merge-sort: Pseudo-código
function merge_sort(m)
if length(m) ≤ 1 return m
var list left, right, result
var integer middle = length(m) / 2
for each x in m up to middle
add x to left
for each x in m after or equal middle
add x to right
left = merge_sort(left)
right = merge_sort(right)
result = merge(left, right)
return result
function merge(left,right)
var list result
while length(left) > 0 or length(right) > 0
if length(left) > 0 and length(right) > 0
if first(left) ≤ first(right)
append first(left) to result
left = rest(left)
else
append first(right) to result
right = rest(right)
else if length(left) > 0
append first(left) to result
left = rest(left)
else if length(right) > 0
append first(right) to result
right = rest(right)
end while
return result