Está en la página 1de 32

Universidad Técnica

de Cotopaxi
Universidad Técnica Sistemas de
de Cotopaxi Información

Facultad:
Ciencias de la Ingeniería y Aplicadas. (C.I.Y.A)
Carrera:
Ingeniería en Informática y Sistemas Computacionales.
Ciclo:
Cuarto.
Integrantes:
 Barrera Guale Edison Fernando.
 Cercado Basurto David Alexander.
 Chiguano Guamangate Franklin Isaias.
 García Fuentes Janara Aslehy.
 Toca Ortega José Wladimir.
 Ulloa Latacunga Bryan Alexander.
Asignatura:
Estructura de Datos.
Tema:
Métodos de Ordenamiento:
 Burbuja Bidireccional.
 Shell Sort.
Docente:
Ing. John Cruz.
Periodo Académico:
Marzo – Agosto 2019.

Extensión La Maná
INTRODUCCIÓN

Muchas actividades humanas requieren que en ellas las diferentes colecciones de elementos

utilizados se coloquen en un orden específico. Las oficinas de correo y las empresas de

mensajería ordenan el correo y los paquetes por códigos postales con el objeto de conseguir

una entrega eficiente; los anuarios o listines telefónicos ordenan sus clientes por orden

alfabético de apellidos con el fin último de encontrar fácilmente el número de teléfono

deseado; los estudiantes de una clase en la universidad se ordenan por sus apellidos o por los

números de expediente, etc. Por esta circunstancia una de las tareas que realizan más

frecuentemente las computadoras en el procesamiento de datos es la ordenación. Existen

varios métodos para ordenar las diferentes estructuras de datos básicas en el momento de

guardar información.

En general los métodos de ordenamiento no son utilizados con frecuencia, en algunos casos

sólo una vez. Hay métodos muy simples de implementar que son útiles en los casos en dónde

el número de elementos a ordenar no es muy grande ya que no ser muy factible al momento

de ponerlo en práctica. Por otro lado, hay métodos sofisticados, más complicados de

implementar pero que son más eficientes en cuestión de tiempo de ejecución.

Los métodos simples son: insertion sort (o por inserción directa) selection sort, bubble sort, y

shellsort, en dónde el último es una extensión al insertion sort, siendo más rápido. Los

métodos más complejos son el quick-sort y sort, radix. El ordenar un grupo de datos significa

mover los datos o sus referencias para que queden en una secuencia tal que represente un

orden, el cual puede ser numérico, alfabético o incluso alfanumérico, ascendente o

descendente.

OBJETIVO

Lograr el entendimiento de cada tema que se dio a conocer en todo el semestre, realizando un

proyecto que está basado en una estructura de datos, en la cual se ha aplicado los
conocimientos adquiridos en este semestre, para poder darnos cuenta que cada tema

estudiado se puede aplicar tanto en la vida cotidiana como a un nivel empresarial.

DESARROLLO

Método de Ordenamiento

Los algoritmos de ordenamiento nos permiten, como su nombre lo dice, ordenar información

de una manera especial basándonos en un criterio de ordenamiento.

En la computación el ordenamiento de datos cumple un rol muy importante, ya sea como un

fin en sí o como parte de otros procedimientos más complejos. Se han desarrollado muchas

técnicas en este ámbito, cada una con características específicas, y con ventajas y desventajas

sobre las demás.

Método burbuja

Este método consiste en comparar pares de elementos adyacentes e intercambiarlos entre si

hasta que todos se encuentren ordenados Se realizan (n-1) pasadas, transportando en cada de

las mismas el menor o mayor elemento (según sea el caso) a su posición ideal. 

Según [ CITATION Der12 \l 12298 ] “El método de ordenamiento de burbuja, es un

algoritmo que se aplica para poder ordenar una cantidad de datos ya sea de forma ascendente

o descendente”.

Es el algoritmo más fácil de implementar, pero a cambio pagamos un alto precio en

procesamiento, ya que este método evalúa los datos muchas veces y en ocasiones

innecesariamente (como por ejemplo cuando son iguales).

El procedimiento de la burbuja es el siguiente: § Ir comparando desde la casilla 0 número tras

número hasta encontrar uno mayor, si este es realmente el mayor de todo el vector se llevará

hasta la última casilla, si no es así, será reemplazado por uno mayor que él. § Este

procedimiento seguirá así hasta que haya ordenado todas las casillas del vector. § Una de las
deficiencias del algoritmo es que ya cuando a ordenado parte del vector vuelve a compararlo

cuando esto ya no es necesario.

Dado un vector a1, a2, a3, ... an 1) Comparar a1 con a2 e intercambiarlos si a1>a2 (o a12) 2)

Seguir hasta que todo se haya comparado an-1 con an 3) Repetir el proceso anterior n-1 veces

Algoritmo: Complejidad for(i=0; i < n-++){ T(n2)

for(j=0; j < n-1; j++){ T(n)

if(vec[j] > vec[j+1]){ T(1)

aux=vec[j]; T(1)

vec[j]=vec[j+1]; T(1)

vec[j+1]=aux;} T(1)

Este método necesita de lo siguiente para implementarse:

 Un array o estructura que ordenar (>1 elemento).

 Dos variables contadoras de ciclos (i,j por ejemplo).

 Una variable temporal (para almacenar un dato momentáneamente).

 Dos ciclos y un Condicional.

Implementación en C:

int temp, i, j;-

for (i = 0; i < util_v -1 ; i++) {

for (j = i + 1; j < util_v ; j++) {

if (v[i] > v[j]) {


temp = v[i];

v[i] = v[j];

v[j] = temp

}
}

El siguiente ejemplo muestra el proceso de forma gráfica:

https://www.ecured.cu/Ordenamiento_de_burbuja

 Burbuja Bidireccional
Según [CITATION And16 \l 12298 ], nos dice que el método de ordenamiento de

burbuja bidireccional es también conocido como:

Ordenamiento cocktail, e intenta mejorar el rendimiento del ordenamiento

burbuja realizando el recorrido de comparación en ambas direcciones, de esta manera

se puede realizar más de un intercambio por iteración.

La manera de trabajar de este algoritmo es ir ordenando al mismo tiempo por los

dos extremos del vector. De manera que, tras la primera iteración, tanto el menor

como el mayor elemento estarán en sus posiciones finales. De esta manera se reduce

el número de comparaciones, aunque la complejidad del algoritmo sigue siendo O(n²).

Ordenamiento de burbuja bidireccional.

Comenzamos con una lista de elementos no ordenados.

Navarro, A. (2016). Lista de Elementos no Ordenados [Figura 1]. Recuperado de


https://juncotic.com/ordenamiento-de-burbuja-bidireccional-algoritmos-de-ordenamiento/

Tomamos los primeros dos números y si no están ordenados se intercambian los

lugares.

Navarro, A. (2016). Proceso de Ordenamiento [Figura 2]. Recuperado de


https://juncotic.com/ordenamiento-de-burbuja-bidireccional-algoritmos-de-ordenamiento/

El proceso continua hasta llegar al final.

  
Navarro, A. (2016). Proceso de Ordenamiento [Figura 3]. Recuperado de
https://juncotic.com/ordenamiento-de-burbuja-bidireccional-algoritmos-de-ordenamiento/

Al llegar al final a diferencia del ordenamiento de burbuja se repite el proceso en

sentido inverso comenzando por el final de la lista hasta llegar al inicio.

Navarro, A. (2016). Proceso de Ordenamiento [Figura 4]. Recuperado de


https://juncotic.com/ordenamiento-de-burbuja-bidireccional-algoritmos-de-ordenamiento/

Al terminar el proceso el último número y el primero ya quedan ordenados por lo

que en la siguiente iteración ya no se evalúan acortando el proceso.

  
Navarro, A. (2016). Proceso de Ordenamiento [Figura 5]. Recuperado de
https://juncotic.com/ordenamiento-de-burbuja-bidireccional-algoritmos-de-ordenamiento/

Al finalizar la segunda iteración se marcan como ordenados el primer y último

número comparado.

No es posible realizar más iteraciones ya que no quedan dos números sin ordenar

para comparar, por lo tanto, el algoritmo termina.

Navarro, A. (2016). Proceso de Ordenamiento [Figura 6]. Recuperado de


https://juncotic.com/ordenamiento-de-burbuja-bidireccional-algoritmos-de-ordenamiento/

Inserción
Explica [ CITATION Ala08 \l 12298 ] que este método se podría decir que es algo superior

al método de la burbuja, ya que logra evaluar menos veces la condición. Sin embargo, aún es

un algoritmo muy pobre y que utiliza recursos técnicamente igual que el algoritmo burbuja.

El algoritmo consiste en ordenar los dos primeros elementos de la matriz, luego se inserta el

tercer elemento en la posición correcta con respecto a los dos primeros, a continuación, se

inserta el cuarto elemento en la posición correcta con respecto a los tres primeros elementos

ya ordenados y así sucesivamente hasta llegar al último elemento de la matriz.

El algoritmo ordena los elementos del arreglo utilizando el método de inserción directa A es

un arreglo de N elementos donde I, aux y k son variables de tipo entero.

1. Repetir con I desde 2 hasta N Hacer aux<- A[I] y k<- I-1

a. Repetir mientras (aux < [k]) y (k > 1) , Hacer A[k+1]<- A[k] y k<-- k-1

b. {fin del ciclo del paso 1.1}

c. Si a[k]<=aux Entonces: Hacer A[k+1]<-aux

Si no Hacer A[k+1]<- A[k], A[k]<-A[k]


d. { fin del condicional del paso 1.3}

2. {fin del condicional del paso1}

Implementación en C

void Insercion(int numbers[], int array_size) {

int i, a, index;

for (i=1; i < array_size; i++) {

index = numbers[i];

a = i-1;

while (a >= 0 && numbers[a] > index) {

numbers[a + 1] = numbers[a];

a--;

numbers[a+1] = index;

Este algoritmo también es bastante sencillo. ¿Has jugado cartas? ¿Cómo las vas ordenando

cuando las recibes? Yo lo hago de esta manera: tomo la primera y la coloco en mi mano. Luego

tomo la segunda y la comparo con la que tengo: si es mayor, la pongo a la derecha, y si es menor

a la izquierda (también me fijo en el color, pero omitiré esa parte para concentrarme en la idea

principal). Después tomo la tercera y la comparo con las que tengo en la mano, desplazándola

hasta que quede en su posición final. Continúo haciendo esto, insertando cada carta en la

posición que le corresponde, hasta que las tengo todas en orden. ¿Lo haces así tú también?

Bueno, pues si es así entonces comprenderás fácilmente este algoritmo, porque es el mismo

concepto.
Para simular esto en un programa necesitamos tener en cuenta algo: no podemos desplazar los

elementos, así como así o se perderá un elemento. Lo que hacemos es guardar una copia del

elemento actual (que sería como la carta que tomamos) y desplazar todos los elementos mayores

hacia la derecha. Luego copiamos el elemento guardado en la posición del último elemento que

se desplazó.

Selección

Algoritmo de ordenamiento por Selección (Selection Sort en inglés): Consiste en encontrar el

menor de todos los elementos del arreglo o vector e intercambiarlo con el que está en la

primera posición. Luego el segundo más pequeño, y así sucesivamente hasta ordenarlo todo.

Su implementación requiere O(n2) comparaciones e intercambios para ordenar una secuencia

de elementos.

Este algoritmo mejora ligeramente el algoritmo de la burbuja. En el caso de tener que ordenar un

vector de enteros, esta mejora no es muy sustancial, pero cuando hay que ordenar un vector de

estructuras más complejas, la operación de intercambiar los elementos sería más costosa en este

caso.

Según [ CITATION Bar11 \l 12298 ] Puede que exista algo de discrepancia en cuanto a si es o no

estable este algoritmo, pero en realidad esta implementación parece ser bastante estable. Se puede

verificar esto ordenando un conjunto de datos que tenga un par de ellos con la misma clave. Se

vera claramente que el orden relativo entre ellos es conservado.

Algunos autores no lo consideran así, pero independientemente de esto, este algoritmo tienes

entre sus ventajas: Es fácil su implementación. No requiere memoria adicional. Realiza pocos

intercambios. Tiene un rendimiento constante, pues existe poca diferencia entre el peor y el mejor

caso. Como todos también tiene algunas desventajas: Es lento y poco eficiente cuando se usa en

listas grandes o medianas. Realiza numerosas comparaciones.


Su funcionamiento se puede definir de forma general como:

 Buscar el mínimo elemento entre una posición i y el final de la lista.

 Intercambiar el mínimo con el elemento de la posición i.

Implementación en C:

void ordsel(int * x, int n){

int minimo=0,i,j;

int swap;

for(i=0 ; i<n-1 ; i++)

minimo=i;

for(j=i+1 ; j<n ; j++)

if (x[minimo] > x[j])

minimo=j;

swap=x[minimo];

x[minimo]=x[i];

x[i]=swap;

}}

Ordenamiento de raíz (radix sort).

Este ordenamiento se basa en los valores de los dígitos reales en las representaciones de

posiciones de los números que se ordenan.


Por ejemplo, el número 235 se escribe 2 en la posición de centenas, un 3 en la posición de

decenas y un 5 en la posición de unidades.

Reglas para ordenar.

 Empezar en el dígito más significativo y avanzar por los dígitos menos significativos

mientras coinciden los dígitos correspondientes en los dos números.

 El número con el dígito más grande en la primera posición en la cual los dígitos de los

dos números no coinciden es el mayor de los dos (por supuesto sí coinciden todos los

dígitos de ambos números, son iguales).

Este mismo principio se toma para Radix Sort, para visualizar esto mejor tenemos el

siguiente ejemplo. En el ejemplo anterior se ordenó de izquierda a derecha. Ahora vamos a

ordenar de derecha a izquierda.

Demostración:

Vector: 25 57 48 37 12 92 86 33

Asignamos colas basadas en el dígito menos significativo.

Parte delantera Parte posterior

2 12 92

3 33

5 25
6 86

7 57 37

8 48

10

Después de la primera pasada:

12 92 33 25 86 57 37 48

Colas basadas en el dígito más significativo.

Parte delantera Parte posterior

1 12

2 25

3 33 37

4 48

5 57

8 86

9 92

10

Vector Ordenado: 12 25 33 37 48 57 86 92

Ventajas

 El ordenamiento es razonablemente eficiente si el número de dígitos en las llaves no

es demasiado grande.
 Si las máquinas tienen la ventaja de ordenar los dígitos (sobre todo si están en binario)

lo ejecutarían con mucho mayor rapidez de lo que ejecutan una comparación de dos

llaves completas.

 Shell Sort

En un documento denominado [CITATION McG19 \n \y \l 12298 ], se encontró

información muy llamativa sobre este tema y nos dice lo siguiente:

La ordenación Shell debe el nombre a su inventor, Donald Shell. Se suele

denominar también ordenación por inserción con incrementos decrecientes. Se

considera que el método Shell es una mejora de los métodos de inserción directa. En

el algoritmo de inserción, cada elemento se compara con los elementos contiguos de

su izquierda, uno tras otro. Si el elemento a insertar es el más pequeño hay que

realizar muchas comparaciones antes de colocarlo en su lugar definitivo. El algoritmo

de Shell modifica los saltos contiguos resultantes de las comparaciones por saltos de

mayor tamaño y con ello se consigue que la ordenación sea más rápida. Generalmente

se toma como salto inicial n/2 (siendo n el número de elementos), luego se reduce el

salto a la mitad en cada repetición hasta que el salto es de tamaño 1. A continuación el

siguiente ejemplo, ordena una lista de elementos siguiendo paso a paso el método de

Shell.
Estructura de Datos. (s.f). Ejemplo Ordenamiento Shell [Figura 7]. Recuperado de
http://novella.mhhe.com/sites/dl/free/844814077x/619434/A06.pdf

Algoritmo de ordenación Shell

Los pasos a seguir por el algoritmo para una lista de n elementos son:

1. Dividir la lista original en n/2 grupos de dos, considerando un incremento o

salto entre los elementos de n/2.

2. Clarificar cada grupo por separado, comparando las parejas de elementos, y

si no están ordenados, se intercambian.

3. Se divide ahora la lista en la mitad de grupos (n/4), con un incremento o

salto entre los elementos también mitad (n/4), y nuevamente se clasifica

cada grupo por separado.

4. Así sucesivamente, se sigue dividiendo la lista en la mitad de grupos que en

el recorrido anterior con un incremento o salto decreciente en la mitad que

el salto anterior, y luego clasificando cada grupo por separado.

5. El algoritmo termina cuando se consigue que el tamaño del salto es 1.

Por consiguiente, los recorridos por la lista están condicionados por el bucle,
Estructura de Datos. (s.f). Comparación de Elementos Indexados [Figura 8]. Recuperado de
http://novella.mhhe.com/sites/dl/free/844814077x/619434/A06.pdf

En el código anterior se observa que se comparan pares de elementos

indexados por j y k, (a[j],a[k]), separados por un salto, intervalo. Así, si n = 8 el

primer valor de intervalo = 4, y los índices i =5, j =1, k =6. Los siguientes valores

de los índices son i = 6, j = 2, k = 7, y así hasta recorrer la lista.

Para realizar un nuevo recorrido de la lista con la mitad de grupos, el

intervalo se hace la mitad:

intervalo  intervalo / 2

Así se repiten los recorridos por la lista, mientras intervalo > 0.

A continuación, según [ CITATION Jos13 \l 12298 ] nos relata una ventaja y

desventaja que tiene este método de ordenamiento denominado Shell Sort.

Ventaja

Shell Sort es más rápido que el Bubble Sort y el Insert Sort.

Desventaja

Su eficiencia no se compara con los métodos de ordenamiento de Merge, Heap

y Quick Sort.

Codificación en C del algoritmo del método Shell

Al codificar en C este método de ordenación se ha de tener en cuenta que el

operador, /, realiza una división entera si los operandos son enteros, y esto es

importante al calcular el ancho del salto entre pares de elementos: intervalo = n/2.

En cuanto a los índices, C toma como base el índice 0 y, por consiguiente, se

ha de desplazar una posición a la izquierda las variables índice respecto a lo

expuesto en el algoritmo. El siguiente código a continuación trata de un programa

desarrollado en C++ que permite definir el tamaño de un Vector y posteriormente


los elementos que lo conforman, según en el orden que sean ingresados, se lo

ordenará por el Método de Shell Sort.

QUICK SORT

El método de ordenamiento rápido (quicksort) es un algoritmo basado en la técnica de divide

y vencerás, que permite, en promedio, ordenar n elementos en un tiempo proporcional a n log

n. Esta es la técnica de ordenamiento más rápida conocida. Fue desarrollada por C. Antony R.

Hoare en 1960. El algoritmo original es recursivo, pero se utilizan versiones iterativas para

mejorar su rendimiento (los algoritmos recursivos son en general más lentos que los

iterativos, y consumen más recursos).

El algoritmo trabaja de la siguiente forma:

 Elegir un elemento del arreglo de elementos a ordenar, al que llamaremos pivote.

 Resituar los demás elementos de la lista a cada lado del pivote, de manera que a un

lado queden todos los menores que él, y al otro los mayores. Los elementos iguales al

pivote pueden ser colocados tanto a su derecha como a su izquierda, dependiendo de la

implementación deseada. En este momento, el pivote ocupa exactamente el lugar que le

corresponderá en la lista ordenada.

 La lista queda separada en dos sublistas, una formada por los elementos a la izquierda

del pivote, y otra por los elementos a su derecha.

 Repetir este proceso de forma recursiva para cada sublista mientras éstas contengan

más de un elemento. Una vez terminado este proceso todos los elementos estarán

ordenados.

Como se puede suponer, la eficiencia del algoritmo depende de la posición en la que termine

el pivote elegido.
 En el mejor caso, el pivote termina en el centro de la lista, dividiéndola en dos

sublistas de igual tamaño. En este caso, el orden de complejidad del algoritmo es O(n·log

n).

 En el peor caso, el pivote termina en un extremo de la lista. El orden de complejidad

del algoritmo es entonces de O(n²). El peor caso dependerá de la implementación del

algoritmo, aunque habitualmente ocurre en listas que se encuentran ordenadas, o casi

ordenadas. Pero principalmente depende del pivote, si por ejemplo el algoritmo

implementado toma como pivote siempre el primer elemento del array, y el array que le

pasamos está ordenado, siempre va a generar a su izquierda un array vacío, lo que es

ineficiente.

 En el caso promedio, el orden es O(n·log n).

No es extraño, pues, que la mayoría de optimizaciones que se aplican al algoritmo se centren

en la elección del pivote.

Función recursiva quicksort para ordenar el arreglo:

void quicksort(int* izq, int* der) {


if (der < izq)
return;

Merge Sort
El algoritmo de ordenamiento por mezcla (merge sort en inglés) es un algoritmo de

ordenamiento externo estable basado en la técnica divide y vencerás. Es de complejidad O(n

log n), fue desarrollado en 1945 por John Von Neuman.

El ordenamiento externo se requiere cuando la información a ordenar no cabe en la memoria

principal de la computadora (RAM) y un tipo de memoria más lenta (Disco Duro) tiene que

utilizarse para el proceso de ordenamiento.


La idea de los algoritmos de ordenación por mezcla es dividir la matriz por la mitad una y

otra vez hasta que cada pieza tenga solo un elemento de longitud. Luego esos elementos se

vuelven a juntar (mezclados) en orden de clasificación.

Función Merge Sort;

function mergesort(m)

var list left, right, result

if length(m) ≤ 1

return m

El funcionamiento del algoritmo es el siguiente:

 Si la longitud de la lista es 0 o 1, la lista ya está ordenada. En cualquier otro caso:

 Dividir la lista en dos sublistas de la mitad de tamaño

 Ordenar cada sublista recursivamente

 Mezclar las dos sublistas en un solo listo ordenado

Una técnica muy poderosa para el diseño de algoritmos es "Dividir para conquistar". Los

algoritmos de este tipo se caracterizan por estar diseñados siguiendo estrictamente las

siguientes fases:

Dividir: Se divide el problema en partes más pequeñas.

Conquistar: Se resuelven recursivamente los problemas más chicos.

Combinar: Los problemas más chicos de combinan para resolver el grande.

Los algoritmos que utilizan este principio son en la mayoría de los casos netamente

recursivos como es el caso de mergesort.

Según [ CITATION Pet16 \l 12298 ] El algoritmo de Mergesort es un ejemplo clásico de

algoritmo que utiliza el principio de dividir para conquistar. Si el vector tiene más de dos
elementos se lo divide en dos mitades, se invoca recursivamente al algoritmo y luego se hace

una intercalación de las dos mitades ordenadas.

Colas
Una cola es un tipo especial de lista abierta en la que sólo se pueden insertar nodos en uno de

los extremos de la lista y sólo se pueden eliminar nodos en el otro. Además, como sucede con

las pilas, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre

eliminan el nodo leído.

Este tipo de lista es conocido como lista FIFO (First In First Out), el primero en entrar es el

primero en salir.

http://programacion-de-lenguaje.blogspot.com/2015/05/colas-en-c.html

El símil cotidiano es una cola para comprar, por ejemplo, las entradas del cine. Los nuevos

compradores sólo pueden colocarse al final de la cola, y sólo el primero de la cola puede

comprar la entrada.

El nodo típico para construir pilas es el mismo que vimos en los capítulos anteriores para la

construcción de listas y pilas:

struct nodo {

   int dato;

   struct nodo *siguiente;

};
Los tipos que definiremos normalmente para manejar colas serán casi los mismos que para

manejar listas y pilas, tan sólo cambiaremos algunos nombres:

typedef struct _nodo {

   int dato;

   struct _nodo *siguiente;

} tipoNodo;

 typedef tipoNodo *pNodo;

typedef tipoNodo *Cola;

tipoNodo es el tipo para declarar nodos, evidentemente.

pNodo es el tipo para declarar punteros a un nodo.

Es evidente, a la vista del gráfico, que una cola es una lista abierta. Así que sigue siendo muy

importante que nuestro programa nunca pierda el valor del puntero al primer elemento, igual

que pasa con las listas abiertas. Además, debido al funcionamiento de las colas, también

deberemos mantener un puntero para el último elemento de la cola, que será el punto donde

insertemos nuevos nodos.

Teniendo en cuenta que las lecturas y escrituras en una cola se hacen siempre en extremos

distintos, lo más fácil será insertar nodos por el final, a continuación del nodo que no tiene

nodo siguiente, y leerlos desde el principio, hay que recordar que leer un nodo implica

eliminarlo de la cola.

PILAS

Una pila es un tipo especial de lista abierta en la que sólo se pueden insertar y eliminar nodos

en uno de los extremos de la lista. Estas operaciones se conocen como "push" y "pop",

respectivamente "empujar" y "tirar". Además, las escrituras de datos siempre son inserciones

de nodos, y las lecturas siempre eliminan el nodo leído.


Estas características implican un comportamiento de lista LIFO (Last In First Out), el último

en entrar es el primero en salir.

Pilas estáticas

Se les llama pilas estáticas puesto que su tamaño se define al momento de su creación y no

puede ser cambiado luego. Este tipo de pilas se implementa con arreglos.

Pilas dinámicas

Las pilas dinámicas trabajan en estructuras que se enlazan para formar la pila, como crear

estas estructuras solo depende de la cantidad de memoria de la que dispone nuestra máquina

podemos crear y enlazar casi tantas como queramos. De ahí el nombre de dinámicas.

https://es.ccm.net/faq/2885-las-pilas-en-lenguaje-c
Operaciones de la Pila

Las pilas tienen algunas operaciones básicas que rigen su uso, a saber:

 new (crear): esta operación crea e inicializa una pila haciendo posible el empezar a
usarla.

 push (encolar): con esta operación agregamos un elemento a la pila, haciendo que la


cantidad de elementos dentro de la pila ascienda en uno.

 pop (desencolar): con esta operación sacamos un elemento de la pila (el último) y


decrementamos la cantidad de elementos de la pila en uno.

 isEmpty (estaVacia): esta operación tiene una respuesta booleana y da verdadero


cuando la pila está vacía y falso cuando no.

 isFull(estaLlena): esta operación tiene una respuesta booleana y da verdadero cuando


la pila está llena y falso cuando no.

 count (cuenta): nos dice cuántos elementos hay almacenados en la pila.

No importa que tipo de elementos contenga nuestra pila, las operaciones son exactamente

iguales. De la misma forma que en el mundo real no importa si la pila es de platos, libros,

cajas, revistas, periódicos… siempre colocamos el último elemento al tope de la pila, y ese

último elemento es el primero que vamos a tomar a la hora de sacar. Ahora bien, si deseamos

abstraer una pila a cualquier lenguaje de programación debemos también respetar la regla o

política de la pila, e implementar sus operaciones básicas.

El símil del que deriva el nombre de la estructura es una pila de platos. Sólo es posible añadir

platos en la parte superior de la pila, y sólo pueden tomarse del mismo extremo.

El nodo típico para construir pilas es el mismo que vimos en el capítulo anterior para la

construcción de listas:

struct nodo {
   int dato;

   struct nodo *siguiente;

};

Los tipos que definiremos normalmente para manejar pilas serán casi los mismos que para

manejar listas, tan sólo cambiaremos algunos nombres:

typedef struct _nodo {

   int dato;

   struct _nodo *siguiente;

} tipoNodo;

typedef tipoNodo *pNodo;

typedef tipoNodo *Pila;

tipoNodo es el tipo para declarar nodos, evidentemente.

pNodo es el tipo para declarar punteros a un nodo.

Pila es el tipo para declarar pilas.

Listas ligadas

La lista enlazada es un TDA que nos permite almacenar datos de una forma organizada, al

igual que los vectores, pero, a diferencia de estos, esta estructura es dinámica, por lo que no

tenemos que saber "a priori" los elementos que puede contener.
Según[ CITATION Ber09 \l 12298 ] Al contrario que las pilas y las colas las listas enlazadas

pueden acceder a una zona de memoria de forma aleatoria, ya que cada trozo de información

lleva un enlace al siguiente elemento de la cadena.

En una lista enlazada, cada elemento apunta al siguiente excepto el último que no tiene

sucesor y el valor del enlace es null. Por ello los elementos son registros que contienen el

dato a almacenar y un enlace al siguiente elemento. Los elementos de una lista, suelen recibir

también el nombre de nodos de la lista.

Estructura de Listas Ligadas

struct lista {

gint dato;

lista *siguiente;

};

  Representa el dato a almacenar. Puede ser de cualquier tipo; en este ejemplo se

trata de una lista de enteros.

  Es un puntero al siguiente elemento de la lista; con este puntero enlazamos con el

sucesor, de forma que podamos construir la lista.


http://www.calcifer.org/documentos/librognome/glib-lists-queues.html

Para que esta estructura sea un TDA lista enlazada, debe tener unos operadores asociados que

permitan la manipulación de los datos que contiene. Los operadores básicos de una lista

enlazada son:

 Insertar: inserta un nodo con dato x en la lista, pudiendo realizarse esta inserción al

principio o final de la lista o bien en orden.

 Eliminar: elimina un nodo de la lista, puede ser según la posición o por el dato.

 Buscar: busca un elemento en la lista.

 Localizar: obtiene la posición del nodo en la lista.

 Vaciar: borra todos los elementos de la lista

Las listas enlazadas se utilizan principalmente para dos propósitos, crear arrays de un tamaño

desconocido en memoria, y los archivos de almacenamiento en disco para bases de datos, las

listas enlazadas permiten insertar y eliminar nuevos elementos.

Las listas pueden ser simplemente enlazadas o doblemente enlazadas, las simplemente

enlazadas contienen un enlace al elemento siguiente, las doblemente enlazadas tanto al

siguiente elemento como al elemento anterior de la lista.

Listas simplemente enlazadas

Una lista simplemente enlazada necesita que cada elemento contenga un enlace con el

siguiente elemento, cada elemento consiste en una estructura de campos de información a

punteros de enlace.
Existen dos formas de construir una lista simplemente enlazada , la primera es añadir un

nuevo elemento al principio o al final de la lista, la otra añade los elementos en un punto

especifico de la lista.

Si la lista ya está ordenada, es conveniente mantenerla así, insertando los nuevos elementos

en su lugar apropiado para lo cual se explora la lista de forma secuencial hasta encontrar el

lugar apropiado, la nueva dirección se inserta en ese punto y los enlaces se vuelven a colocar

como sea necesario.

Se pueden dar tres posibles situaciones al insertar un elemento en una lista enlazada

Primero: El elemento se puede convertir en el primer elemento.

Segundo: Puede ser insertado entre otros dos elementos.

Tercero: Se puede convertir en el último elemento de la lista.

Tener en cuenta que al cambiar el primer elemento hay que actualizar el punto de entrada en

alguna parte del programa, también se puede utilizar un centinela, que no es

más que el primer elemento no cambia nunca con un valor especial, con lo que siempre será

el primer elemento de la lista, pero se necesita una posición más de memoria. Para recuperar

un elemento de la lista es como seguir una cadena, una rutina basada en el campo nombre.

Para borrar un elemento al igual que para insertar un elemento se pueden dar los mismos tres

casos, si se borra el primer elemento de la lista el puntero previo ha de hacerse nulo, y la

función tiene que devolver un puntero al comienzo de la lista para que cuando se borre el

primer elemento de la lista, el programa conozca la dirección del nuevo primer elemento de la

lista. Las listas simplemente enlazadas solo se pueden recorrer en sentido ascendente y no en

sentido descendente, para lo cual se pueden utilizar las listas doblemente enlazadas.
Listas doblemente enlazadas.

Las listas doblemente enlazadas consisten en datos y enlaces tanto al elemento siguiente

como al elemento anterior. Con lo que se consiguen dos grandes ventajas, primero la lista se

puede leer en cualquier dirección, la segunda es que se pueden leer los enlaces hacia delante

como hacia atrás, con lo que si un enlace resulta no valido se puede reconstruir utilizando el

otro enlace.

Como en las listas simplemente enlazadas, las doblemente enlazadas pueden contener una

función que almacene cada elemento en una posición especifica de la lista a medida que esta

se construye, en lugar de colocar cada elemento al final de la lista.

Árbol binario

En ciencias de la computación, un árbol binario es una estructura de datos en la cual cada


nodo puede tener un hijo izquierdo y un hijo derecho. No pueden tener más de dos hijos (de
ahí el nombre "binario"). Si algún hijo tiene como referencia a null, es decir que no almacena
ningún dato, entonces este es llamado un nodo externo. En el caso contrario el hijo es
llamado un nodo interno. Usos comunes de los árboles binarios son los árboles binarios de
búsqueda, los montículos binarios y Codificación de Huffman.

Un árbol binario sencillo de


tamaño 9, 3 niveles (nivel 0
hasta nivel 3) y altura 3 (altura =
máximo nivel), con un nodo raíz
cuyo valor es 2

Un árbol binario puede declararse de varias


maneras. Algunas de ellas son:
Estructura con manejo de memoria dinámica, siendo el puntero que apunta al árbol de tipo
tArbol:

typedef struct nodo {


int clave;
struct nodo *izdo, *dcho;
}Nodo;

Recorridos sobre árboles binarios

El método de este recorrido es tratar de encontrar de la cabecera a la raíz en nodo de unidad


binaria. Ahora pasamos a ver la implementación de los distintos recorridos:

 Recorrido en pre orden

En este tipo de recorrido se realiza cierta acción (quizás simplemente imprimir por pantalla el
valor de la clave de ese nodo) sobre el nodo actual y posteriormente se trata el subárbol
izquierdo y cuando se haya concluido, el subárbol derecho. Otra forma para entender el
recorrido con este método seria seguir el orden: nodo raíz, nodo izquierda, nodo derecha.

void preorden(tArbol *a)


{
if (a != NULL) {
tratar(a); //Realiza una operación en nodo
preorden(a->hIzquierdo);
preorden(a->hDerecho);
}
}

 Recorrido en post orden

En este caso se trata primero el subárbol izquierdo, después el derecho y por último el nodo
actual. Otra forma para entender el recorrido con este método seria seguir el orden: nodo
izquierda, nodo derecha, nodo raíz. En el árbol de la figura el recorrido en post orden sería: 2,
5, 11, 6, 7, 4, 9, 5 y 2.
void postorden(tArbol *a)
{
if (a != NULL) {
postorden(a->hIzquiedo);
postorden(a->hDerecho);
tratar(a); //Realiza una operación en nodo
}
}

 Recorrido en in orden

En este caso se trata primero el subárbol izquierdo, después el nodo actual y por último el
subárbol derecho. En un ABB este recorrido daría los valores de clave ordenados de menor a
mayor. Otra forma para entender el recorrido con este método seria seguir el orden: nodo
izquierda, nodo raíz, nodo derecha. En el árbol de la figura el recorrido en in orden sería: 2, 7,
5, 6, 11, 2, 5, 4, 9.

void inorden(tArbol *a)


{
if (a != NULL) {
inorden(a->hIzquierdo);
tratar(a); //Realiza una operación
en nodo
inorden(a->hDerecho);
}
}
TRIE

Un trie es una estructura de datos de tipo árbol que permite la recuperación de información
(de ahí su nombre del inglés reTRIEval). La información almacenada en un trie es un
conjunto de claves, donde una clave es una secuencia de símbolos pertenecientes a un
alfabeto. Las claves son almacenadas en las hojas del árbol y los nodos internos son pasarelas
para guiar la búsqueda. El árbol se estructura de forma que cada letra de la clave se sitúa en
un nodo de forma que los hijos de un nodo representan las distintas posibilidades de símbolos
diferentes que pueden continuar al símbolo representado por el nodo padre. Por tanto la
búsqueda en un trie se hace de forma similar a como se hacen las búsquedas en un
diccionario:

Se empieza en la raíz del árbol. Si el símbolo que estamos buscando es A entonces la


búsqueda continua en el subárbol asociado al símbolo A que cuelga de la raíz. Se sigue de
forma análoga hasta llegar al nodo hoja. Entonces se compara la cadena asociada al nodo
hoja y si coincide con la cadena de búsqueda entonces la búsqueda ha terminado en éxito,
si no entonces el elemento no se encuentra en el árbol.

Por eficiencia se suelen eliminar los nodos intermedios que sólo tienen un hijo, es decir, si un
nodo intermedio tiene sólo un hijo con cierto carácter entonces el nodo hijo será el nodo hoja
que contiene directamente la clave completa.

Es muy útil para conseguir búsquedas eficientes en repositorios de datos muy voluminosos.
La forma en la que se almacena la información permite hacer búsquedas eficientes de cadenas
que comparten prefijos.

CONCLUSIÓN:
 En la vida cotidiana no es muy común utilizar el método de ordenamiento, pero sin

embargó lo implementan en algún momento se necesitará realizar una búsqueda y

para este tipo de búsquedas tiene que ser un método eficiente he utilizable que no

produzca errores el momento de ejecutarlo, por lo general de utilizan los métodos

simples para este tipo de proyectos

 Cada tema enseñado en clase ha Sido fundamental para nosotros al momento de

realizar este proyecto ya que nos ha sido muy útil poner en práctica nuestros

conocimientos y de esta manera poderlo resolver de mejor manera y con gran

dedicación.

Bibliografía
Amey, P. (2016). Closing the loop - the influence of code analysis on desing. Vietna : Ada - Europe.

Andrea Navarro. (25 de Octubre de 2016). Junco TIC. Obtenido de Ordenamiento de burbuja
bidireccional - Algoritmos de ordenamiento - Junco TIC: https://juncotic.com/ordenamiento-
de-burbuja-bidireccional-algoritmos-de-ordenamiento/

Burns, A., & Wellings, A. (2008). Sistemas de tiempo real y lenguajes de programación , 3rd Edición.
Addison Wesley.

Joshtyn Mejias. (19 de Octubre de 2013). PREZI. Obtenido de METODO DE ORDENAMIENTO SHELL
SORT: https://prezi.com/rpa3rqilg-bz/metodo-de-ordenamiento-shell-sort/

Knuth, D. (2012). The art of computer programming , vol 3 : Sorting and searching. Addison - Wesley.

Liskov, B. (2011). Abstraction ande specification in program development . MIT Press.

Mc Graw Hill Education. (15 de Mayo de 2019). Algoritmos y Estructuras de Datos. Obtenido de
Algoritmos de Ordenación y Búsqueda:
http://novella.mhhe.com/sites/dl/free/844814077x/619434/A06.pdf

Meyer, B. (2009). Construcción de software orientada a objetos , 2nd Edition. Prentice.

También podría gustarte