66
MATERIA: ESTRUCTURA DE DATOS LI. MA. DE LA LUZ AYAR MARTINEZ Unidad 1 Tipos de datos 1.1 Tipos de Datos Simples: estructura de datos Son todos aquellos que abarcan una sola casilla de memoria como los boleanos, enteros, flotantes, etc. Estructurales: Arreglos de cadenas, pilas o estructuras, abarcan mas de una casilla de memoria. TABLA COMUN DE TIPOS DE DATOS TIPO RANGO BYTES E N T E R O S Entero −32,768 a 32,767 2 Entero sin signo 0 a 65,535 2 Corto −32,768 a 32,767 2 Corto sin signo 0 a 65,535 2 Largo entero −2,147,483,648 a 2,147,483,295 4 Largo sin signo 0 a 4,294,967,295 4 C A R A C T E R Caracter −128 a 127 1 Caracter sin signo 0 a 255 1 DE PUNTO FLOTANTE Flotante 3.4 −38 a 3.4 38 4 Doble 1.7 −308 a 1.7 308 8 Largo doble 3.4 −4932 a 3.4 4932 10 Primitivos: No tienen “descomposición”, están predefinidos en el lenguaje. Tipos compuestos:

Unidad 1 Tipos de datos - Luzayar's Weblog | Just … · Web viewUn ejemplo de un conjunto de símbolos es {0,1,2,3,4,5,6,7,8,9,A,B,C….Y,z,¡,-,+,*} en el cual se incluyen dígitos,

Embed Size (px)

Citation preview

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Unidad 1 Tipos de datos 1.1 Tipos de Datos Simples: estructura de datos Son todos aquellos que abarcan una sola casilla de memoria como los boleanos, enteros, flotantes, etc.

Estructurales:

Arreglos de cadenas, pilas o estructuras, abarcan mas de una casilla de memoria. TABLA COMUN DE TIPOS DE DATOS

 TIPO RANGO BYTES       E N T E R O S  Entero −32,768 a 32,767 2Entero sin signo 0 a 65,535 2Corto −32,768 a 32,767 2Corto sin signo 0 a 65,535 2Largo entero −2,147,483,648 a 2,147,483,295 4Largo sin signo 0 a 4,294,967,295 4       C A R A C T E R  Caracter −128 a 127 1Caracter sin signo 0 a 255 1       DE PUNTO FLOTANTE  Flotante 3.4−38 a 3.438 4Doble 1.7−308 a 1.7308 8Largo doble 3.4−4932 a 3.44932 10

Primitivos:

No tienen “descomposición”, están predefinidos en el lenguaje.

Tipos compuestos:

Aparte de los anteriores, C++ soporta tipos compuestos (también denominados tipos-clase). Son compuestos o agregados de tipos básicos, por esta razón se les denomina también tipos agregados o abstractos ADTs (“Abstract data types”). El “material” de que están compuestos son los tipos básicos, bien en estado “puro” o en sus diversas

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

“adaptaciones”. El proceso es recursivo, de forma que un tipo complejo puede contener miembros que son a su vez tipos complejos y así sucesivamente.

Desde el punto de vista semántico la gramática C++ establece como tipos compuestos (“Compound types”) los siguientes:

Arreglos. Matrices de objetos de cualquier tipo. Funciones, que aceptan parámetros de ciertos tipos y devuelven void u objetos

(o referencias a objetos) de cierto tipo. Punteros a-void; punteros a-objetos, o punteros a-función (incluyendo miembros

estáticos de clases) de un tipo determinado. Punteros a miembros no-estáticos de clases (que señalan miembros de un tipo

determinado dentro de objetos de una clase determinada). Referencias a objetos o funciones de un tipo determinado. Clases. Uniones.

Tambien existen tipos de datos definidos por el usuario que varian sus sintaxis segun el lenguaje de programación.

1.1.1 Tipos de Datos Simples Tipos de datos simples

Es uno de los conceptos fundamentales de cualquier lenguaje de programación. Estos definen los métodos de almacenamiento disponibles para representar información, junto con la manera en que dicha información ha de ser interpretada.

Para crear una variable (de un tipo simple) en memoria debe declararse indicando su tipo de variable y su identificador que la identificará de forma única. La sintaxis de declaración de variables es la siguiente: Tipo Simple Identificador1, Identificador2; Esta sentencia indica al compilador que reserve memoria para dos variables del tipo simple Tipo Simple con nombres Identificador1 e Identificador2.

Los tipos de datos en Java pueden dividirse en dos categorías: simples y compuestos. Los simples son tipos nucleares que no se derivan de otros tipos, como los enteros, de coma flotante, booleanos y de carácter. Los tipos compuestos se basan en los tipos

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

simples, e incluyen las cadenas, las matrices y tanto las clases como las interfaces, en general.

Cada tipo de datos simple soporta un conjunto de literales que le pueden ser asignados, para darles valor. En este apartado se explican los tipos de datos simples (o primitivos) que presenta Java, así como los literales que soporta (sintaxis de los valores que se les puede asignar).

a.) Tipos de datos enteros

Se usan para representar números enteros con signo. Hay cuatro tipos: byte, short, int y long.

Tipo Tamaño

byte 1Byte (8 bits)

short 2 Bytes (16 bits)

int 4 Bytes (32 bits)

long 8 Bytes (64 bits)

Tabla 5: Tipos de datos enteros

Literales enteros

Son básicos en la programación en Java y presentan tres formatos:

Decimal: Los literales decimales aparecen como números ordinarios sin ninguna notación especial.

Hexadecimal: Los hexadecimales (base 16) aparecen con un 0x ó 0X inicial, notación similar a la utilizada en C y C++.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Octal: Los octales aparecen con un 0 inicial delante de los dígitos.

Por ejemplo, un literal entero para el número decimal 12 se representa en Java como 12 en decimal, como 0xC en hexadecimal, y como 014 en octal.

Los literales enteros se almacenan por defecto en el tipo int, (4 bytes con signo), o si se trabaja con números muy grandes, con el tipo long, (8 bytes con signo), añadiendo una L ó l al final del número.

La declaración de variables enteras es muy sencilla. Un ejemplo de ello sería:

long numeroLargo = 0xC; // Por defecto vale 12

b.) Tipos de datos en coma flotante

Se usan para representar números con partes fraccionarias. Hay dos tipos de coma flotante: float y double. El primero reserva almacenamiento para un número de precisión simple de 4 bytes y el segundo lo hace para un numero de precisión doble de 8 bytes.

Tipo Tamaño

float 4 Byte (32 bits)

double 8 Bytes (64 bits)

Tabla 6: Tipos de datos numéricos en coma flotante

Literales en coma flotante

Representan números decimales con partes fraccionarias. Pueden representarse con notación estándar (563,84) o científica (5.6384e2).

De forma predeterminada son del tipo double (8 bytes). Existe la opción de usar un tipo más corto (el tipo float de 4 bytes), especificándolo con una F ó f al final del número.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

La declaración de variables de coma flotante es muy similar a la de las variables enteras. Por ejemplo:

double miPi = 314.16e-2 ; // Aproximadamente

float temperatura = (float)36.6; // Paciente sin fiebre

Se realiza un moldeado a temperatura, porque todos los literales con decimales por defecto se consideran double.

c.) Tipo de datos boolean

Se usa para almacenar variables que presenten dos estados, que serán representados por los valores true y false. Representan valores bi-estado, provenientes del denominado álgebra de Boole.

Literales Booleanos

Java utiliza dos palabras clave para los estados: true (para verdadero) y false (para falso). Este tipo de literales es nuevo respecto a C/C++, lenguajes en los que el valor de falso se representaba por un 0 numérico, y verdadero cualquier número que no fuese el 0.

Para declarar un dato del tipo booleano se utiliza la palabra reservada boolean:

boolean reciboPagado = false; // ¡¿Aun no nos han pagado?!

d.) Tipo de datos carácter

Se usa para almacenar caracteres Unicode simples. Debido a que el conjunto de caracteres Unicode se compone de valores de 16 bits, el tipo de datos char se almacena en un entero sin signo de 16 bits.

Java a diferencia de C/C++ distingue entre matrices de caracteres y cadenas.

Literales carácter

Representan un único carácter (de la tabla de caracteres Unicode 1.1) y aparecen dentro de un par de comillas simples. De forma similar que en C/C++. Los caracteres

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

especiales (de control y no imprimibles) se representan con una barra invertida (‘\’) seguida del código carácter.

Descripción Representación Valor Unicode

Caracter Unicode \udddd

Numero octal \ddd

Barra invertida \u005C

Continuación Retroceso \b \u0008

Retorno de carro \r \u000D

Alimentación de formularios \f \u000C

Tabulación horizontal \t \u0009

Línea nueva \n \u000A

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Comillas simples \’ \u0027

Comillas dobles \” \u0022

Números arábigos ASCII 0–9 \u0030 a \u0039

Alfabeto ASCII en mayúsculas A.-Z \u0041 a \u005A

Alfabeto ASCII en minúsculas a.-z \u0061 a \u007A

Tabla 7: Caracteres especiales Java

Las variables de tipo char se declaran de la siguiente forma:

char letraMayuscula = ‘A’; // Observe la necesidad de las ‘ ‘

char letraV = ‘\u0056′; // Letra ‘V’

e.) Conversión de tipos de datos

En Java es posible transformar el tipo de una variable u objeto en otro diferente al original con el que fue declarado. Este proceso se denomina “conversión”, “moldeado” o “tipado”. La conversión se lleva a cabo colocando el tipo destino entre paréntesis, a la izquierda del valor que queremos convertir de la forma siguiente:

char c = (char)System.in.read();

La función read devuelve un valor int, que se convierte en un char debido a la conversión (char), y el valor resultante se almacena en la variable de tipo carácter c.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

El tamaño de los tipos que queremos convertir es muy importante. No todos los tipos se convertirán de forma segura. Por ejemplo, al convertir un long en un int, el compilador corta los 32 bits superiores del long (de 64 bits), de forma que encajen en los 32 bits del int, con lo que si contienen información útil, esta se perderá.

Por ello se establece la norma de que “en las conversiones el tipo destino siempre debe ser igual o mayor que el tipo fuente”:

Tipo Origen Tipo Destino

byte double, float, long, int, char, short

short double, float, long, int

char double, float, long, int

int double, float, long

long double, float

float double

Tabla 8: Conversiones sin pérdidas de información

1.1.1.1 Definicion Bit Byte Caracter Palabra

1.1.1 DEFINICIÓN DE BIT, BYTE, CARÁCTER Y PALABRA

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Bit: es una síntesis de dos términos en inglés: Binary digit, que en español significan dígito binario, o lo que es lo mismo, número (dígito) con dos posibles valores (binario). El término surge de usar las dos primeras letras de Binary con la última de digit.: bit. Es la unidad de información más sencilla posible en el sistema binario.

Byte: Unidad de información que consta de 8 bits equivalente a un único caracter, como una letra, número o signo de puntuación.

Caracter: Es un elemento tomado de un conjunto de símbolos. Un ejemplo de un conjunto de símbolos es {0,1,2,3,4,5,6,7,8,9,A,B,C….Y,z,¡,-,+,*} en el cual se incluyen dígitos, los caracteres del alfabeto y algunos caracteres especiales. Un compilador de lenguaje reconoce un conjunto particular de caracteres.

Palabra: Conjunto de bits que, como unidad elemental, puede manipular una computadora. La longitud en bits de una palabra en una computadora puede ser de 8, 16, 32, etc., y depende del microprocesador de su unidad central de proceso.

1.1.1.2 Manipulacion de Bits

1.1.1.3 Representacion Datos Simples 1.1.2 Tipos Datos Abstractos 1.2 Estructuras de Datos Definicion

Estructura de datos

En programación, una estructura de datos es una forma de organizar un conjunto de datos elementales (un dato elemental es la mínima información que se tiene en el sistema) con el objetivo de facilitar la manipulación de estos datos como un todo o individualmente.

Una estructura de datos define la organización e interrelacionamiento de estos, y un conjunto de operaciones que se pueden realizar sobre él. Las operaciones básicas son:

Alta, adicionar un nuevo valor a la estructura. Baja, borrar un valor de la estructura. Búsqueda, encontrar un determinado valor en la estructura para realizar una operación con este valor, en forma SECUENCIAL o BINARIO (siempre y cuando los datos estén ordenados)…

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Otras operaciones que se pueden realizar son:

Ordenamiento, de los elementos pertenecientes a la estructura.

Apareo, dadas dos estructuras originar una nueva ordenada y que contenga a las apareadas.

Cada estructura ofrece ventajas y desventajas en relación a la simplicidad y eficiencia para la realización de cada operación. De esta forma, la elección de la estructura de datos apropiada para cada problema depende de factores como la frecuencia y el orden en que se realiza cada operación sobre los datos.

1.2.2 Clasificacion Estructuras de Datos

1.2.2.1 Estructuras de Datos Lineales y no Lineales 1.2.2.2 Estructura de Datos Dinamicas y Estaticas

UNIDAD 2 ESTRUCTURAS LINEALES

2.1 Arreglos

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

2.1.1 Definicion

Arreglo: Es un acomodo de espacios (Como en una matriz) en los cuales es una colección de un tipo de dato, y pueden ser unidimensionales, bidimesionales o multidimensionales

Es un conjunto finito y ordenado de elementos homogéneos (del mismo tipo de datos). Es un tipo de dato estructurado simple o estático y pueden ser vectores o tablas (matrices).

En lenguaje C, se pueden definir conjuntos de datos conocidos como arreglos. Por ejemplo, si deseáramos guardar en un arreglo, diez valores enteros, debemos definir este arreglo de la siguiente manera: int elem[10]; Esta expresión es la declaración del arreglo. Donde int es el tipo de datos que almacena el arreglo, elem es el nombre del arreglo, y el número encerrado en los corchetes es el número de valores que contiene el arreglo. Cabe hacer notar que, el índice para el primer elemento es 0 y, el valor máximo del índice es igual a n-1 elementos del arreglo. En nuestro caso, el último elemento del arreglo elem será elem[9]. El programador deberá tener cuidado de no indicar elementos inexistentes en el arreglo, es decir, elementos cuyos índices son números con signo menores a 0 o elementos con índices mayores a los n-1 elementos del arreglo. De no-tener cuidado, el compilador de C no marcará error alguno, pero se produce un error en tiempo de ejecución.

Un arreglo se puede entender mejor representándolo como en la figura

Representación de un arreglo lineal.

Un punto importante es que, el nombre del arreglo es, por si mismo, un apuntador a la localidad de memoria que ocupa el primer elemento, es decir, el nombre del arreglo es una variable que contiene la dirección del primer elemento. Esto se puede expresar como sigue:

elem = &elem[0]

A continuación se presenta un programa que emplea arreglos para mostrar una serie de números y la palabra “hola”.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

int main(void)

{

int y; int numeros[4] = {2, 4, 6, 8}; char palabra[ ] = {’h’, ‘o’, ‘l’, ‘a’,’\0′}; for (y=0; y<4; y++)

printf (“números [%d] = %d\n”, y, números[y] ); printf(“\n”); for (y=0; y<4; y++)

printf (“%c”, palabra[y] ); return (0); } ¿ Cuál es el resultado de la ejecución del programa anterior? En el ejemplo, la forma de inicialización del arreglo números solo es soportada por el estándar ANSI.

Operaciones Con Arreglos

Las operaciones en arreglos pueden clasificarse de la siguiente forma:

Lectura

Escritura

Asignación

Actualización

Ordenación

Búsqueda

a) LECTURA

Este proceso consiste en leer un dato de un arreglo y asignar un valor a cada uno de sus componentes.

La lectura se realiza de la siguiente manera:

para i desde 1 hasta N haz

x<--arreglo[i]

b) ESCRITURA

Consiste en asignarle un valor a cada elemento del arreglo.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

La escritura se realiza de la siguiente manera:

para i desde 1 hasta N haz

arreglo[i]<--x

c) ASIGNACION

No es posible asignar directamente un valor a todo el arreglo, por lo que se realiza de la manera siguiente:

para i desde 1 hasta N haz

arreglo[i]<--algún_valor

d) ACTUALIZACION

Dentro de esta operación se encuentran las operaciones de eliminar, insertar y modificar datos. Para realizar este tipo de operaciones se debe tomar en cuenta si el arreglo está o no ordenado.

Para arreglos ordenados los algoritmos de inserción, borrado y modificación son los siguientes:

1.- Insertar.

Si i< mensaje(arreglo contrario caso En arreglo[i]<--valor i<--i+1 entonces>

2.- Borrar.

Si N>=1 entonces

inicio

i<--1

encontrado<--falso

mientras i<=n y encontrado=falso

inicio

si arreglo[i]=valor_a_borrar entonces

inicio

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

encontrado<--verdadero

N<--N-1

para k desde i hasta N haz

arreglo[k]<--arreglo[k-1]

fin

en caso contrario

i<--i+1

fin

fin

Si encontrado=falso entonces

mensaje (valor no encontrado)

3.- Modificar.

Si N>=1 entonces

inicio

i<--1

encontrado<--falso

mientras i<=N y encontrado=false haz

inicio

Si arreglo[i]=valor entonces

arreglo[i]<--valor_nuevo

encontrado<--verdadero

En caso contrario

i<--i+1

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

fin

fin

2.1.2 Arreglos Unidimensionales

Un arreglo unidimensional es un tipo de datos estructurado que está formado de una colección finita y ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de elementos iguales.

El tipo de acceso a los arreglos unidimensionales es el acceso directo, es decir, podemos acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa.

Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior.

REPRESENTACION EN MEMORIA

Los arreglos se representan en memoria de la forma siguiente:                 x : array[1..5] of integer

Para establecer el rango del arreglo (número total de elementos) que componen el arreglo se utiliza la siguiente formula:

                RANGO = Ls - (Li+1)donde:

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

ls = Límite superior del arreglo

li = Límite inferior del arreglo

Para calcular la dirección de memoria de un elemento dentro de un arreglo se usa la siguiente formula:

                A[i] = base(A) + [(i-li) * w]donde :

A = Identificador único del arreglo

i = Indice del elemento

li = Límite inferior

w = Número de bytes tipo componente

Si el arreglo en el cual estamos trabajando tiene un índice numerativo utilizaremos las siguientes fórmulas:

                RANGO = ord (ls) - (ord (li)+1)                A[i] = base (A) + [ord (i) - ord (li) * w]

2.1.3 Arreglos Bidimensionales

Este tipo de arreglos al igual que los anteriores es un tipo de dato estructurado, finito ordenado y homogéneo. El acceso a ellos también es en forma directa por medio de un par de índices.

Los arreglos bidimensionales se usan para representar datos que pueden verse como una tabla con filas y columnas. La primera dimensión del arreglo representa las columnas, cada elemento contiene un valor y cada dimensión representa una relación

La representación en memoria se realiza de dos formas : almacenamiento por columnas o por renglones.

Para determinar el número total de elementos en un arreglo bidimensional usaremos las siguientes fórmulas:

RANGO DE RENGLONES (R1) = Ls1 - (Li1+1)

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

RANGO DE COLUMNAS (R2) = Ls2 - (Li2+1)

No. TOTAL DE COMPONENTES = R1 * R2

REPRESENTACION EN MEMORIA POR COLUMNAS

x : array [1..5,1..7] of integer

Para calcular la dirección de memoria de un elemento se usan la siguiente formula:

A[i,j] = base (A) + [((j - li2) R1 + (i + li1))*w]

REPRESENTACION EN MEMORIA POR RENGLONES

x : array [1..5,1..7] of integer

Para calcular la dirección de memoria de un elemento se usan la siguiente formula:

A[i,j] = base (A) + [((i - li1) R2 + (j + li2))*w]

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

donde:

i = Indice del renglón a calcular

j = Indice de la columna a calcular

li1 = Límite inferior de renglones

li2 = Límite inferior de columnas

w = Número de bytes tipo componente

2.1.4 Arreglos Multidimensionales

Este también es un tipo de dato estructurado, que está compuesto por n dimensiones. Para hacer referencia a cada componente del arreglo es necesario utilizar n índices, uno para cada dimensión

Para determinar el número de elementos en este tipo de arreglos se usan las siguientes fórmulas:

RANGO (Ri) = lsi - (lii + 1)

No. TOTAL DE ELEMENTOS = R1 * R2* R3 * ...* Rn

donde:

i = 1 ... n

n = No. total de dimensiones

Para determinar la dirección de memoria se usa la siguiente formula:

LOC A[i1,i2,i3,...,in] = base(A) + [(i1-li1)*R3*R4*Rn + (i2-li2)*R3*R2*... (in - lin)*Rn]*w

2.1.5 Resolución de problemas con arreglos

Practicas2.1.6 Clases para Implementación de Arreglos

La computadora guarda los distintos tipos de datos de una forma lógica de tal manera que pueda encontrar los valores de forma rápida y eficiente. La forma

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

como son guardados los datos se llama estructura de los datos, de aquí el término de datos estructurados . La variable , usada en las unidades anteriores, es una manera de estructurar datos, al igual que el archivo (estructura consistente en una secuencia de componentes del mismo tipo, normalmente un record) y el record (estructura formada por un número fijo o variable de elementos, denominados campos, que pueden ser de diferentes tipos de datos, pero todos ellos representan el record como un todo). La sintaxis de la estructura de un record para almacenar una fecha, por ejemplo en Pascal, sería:   Type fecha = record Dia : 1 .. 31; Mes : (en, feb, .., dic); Year : (1990 .. 2010); End El valor de estas variable se guarda en un lugar específico, previamente declarado, de la memoria. Estas son las estructuras de datos más simples. Otro tipo de estructuras de datos o de datos estructurados es el arreglo o array.   Se conoce como arreglo o array cuando se designa más de una localización de la memoria para el nombre una sola variable. A los arreglos también se les conoce como tablas , término proveniente de los negocios, donde los datos se colocan en las celdas de la tabla. Es una gran ventaja poder guardar muchos valores para la misma variable en la memoria principal o interna de la computadora, porque así se aumenta el tiempo de procesamiento. Este múltiple almacenamiento significa que el nombre de una variable tiene más de una localización en la memoria de la computadora.   Los arreglos se utilizan con mucha frecuencia en el proceso de solución de problemas. Un programador que tiene muchos valores de datos de un mismo estilo –muchas edades, temperaturas, nombres, etc.– puede guardarlos en la computadora en forma de un arreglo, permitiendo una lectura y un uso más fácil. El programador también puede usar los valores de un arreglo para apuntar a los valores de otro arreglo (se conoce como Técnica del Puntero, pues el valor de un elemento en el primer arreglo apunta a otro elemento en el segundo arreglo). Sin los arreglos esta tarea se haría muy tediosa.  

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

El programador utiliza el arreglo cuando en la solución de un problema hay que utilizar más de un valor en una variable—por ejemplo, cuando se calcula el porciento de ventas de cada tienda de una compañía que tiene varias tiendas. La venta de las tiendas es una variable que tiene más de un valor, un valor por cada tienda.   El programador dice a la computadora cuántas localizaciones de memoria necesita para guardar en un arreglo mediante una instrucción especial o al momento de definir los tipos de datos. El número de localizaciones de memoria donde se guarda es igual o mayor al número de localizaciones usadas en la solución. Si es menor al número de localizaciones usadas, tira un error. Hay dos clases de arreglos, el estático y el dinámico. En el arreglo estático no puede cambiarse el número de localizaciones a no ser que se cambien las instrucciones. En el arreglo dinámico , usado por algunos lenguajes, el programador asigna el número de localizaciones como una variable, que puede expandirse o reducirse durante la ejecución de la solución; este arreglo es más flexible y usa menos espacio de memoria que el estático, pero consume más tiempo durante el proceso.   Cada localización de la memoria se llama un elemento, al que se le asigna un número o números correspondientes a la posición de la localización en el arreglo. Este número es un número de referencia relativo a la localización del primer valor del arreglo. El nombre del elemento tiene dos partes. La primera parte es el nombre de la variable; la segunda parte es el número de referencia, conocido también como index number o element number entre paréntesis (corchetes en Pascal).   AGE(5)   En el siguiente arreglo la variable a contiene un arreglo de diez valores enteros:   En Pascal a: array [1...10] of integer   o en FORTRAN  

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

INTEGER a(10)   Algunos lenguajes inician el primer elemento del arreglo con cero , en lugar del uno . Se recomienda, si el lenguaje lo permite, empezar el arreglo con el uno, de tal forma que coincida el primer elemento del arreglo con el número 1 y no con el 0.   No es necesario usar el arreglo en un orden especial. Los datos usados como valores de los elementos han de tener el mismo tipo de dato tal como fue identificado al nominar la variable del arrgelo. En la instrucción asignada (forma de variable), puede asignarse el valor de una constante, una variable o una expresión a un elemento.

2.2 Pilas

2.2.1 Definición

Las pilas son otro tipo de estructura de datos lineales, las cuales presentan restricciones en cuanto a la posición en la cual pueden realizarse las inserciones y las extracciones de elementos. Una pila es una lista de elementos en la que se pueden insertar y eliminar elementos sólo por uno de los extremos. Como consecuencia, los elementos de una pila serán eliminados en orden inverso al que se insertaron. Es decir, el último elemento que se metió a la pila será el primero en salir de ella. En la vida cotidiana existen muchos ejemplos de pilas, una pila de platos en una alacena, una pila de latas en un supermercado, una pila de papeles sobre un escritorio, etc. Debido al orden en que se insertan y eliminan los elementos en una pila, también se le conoce como estructura LIFO (Last In, First Out: último en entrar, primero en salir).

2.2.2 Operaciones con Pilas

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Una Pila se compone de los siguientes elementos:ç arreglo de datos El numero maximo El numero minimo El tipo de datos de la pila los indices Tope y Base de la Pila

Operaciones Elementales Iniciar Insertar Eliminar

Axiomas

Insertar: Si Tope = Maximo Mensaje( O Verflow?)de lo Contrario

Tope = Tope +1 Pila Tope = Valor

2.2.3 Clases para Implementacion de Pilas

Ejemplo completo sobre la implementación de pilas manejando Visual Studio .net 2003 //----LIO

1. include “stdafx.h” 2. using <mscorlib.dll>

using namespace System;

using namespace System::Collections; public __gc class Ejemplo Stack ? {

public: static void Imprime(I Enumerable ? __gc *Mi Coleccion ? )

{ System::Collections::I Enumerator ? __gc *Mi Enumerador ? = Mi Coleccion→Get Enumerator ? (); while (Mi Enumerador→Move Next ? ())

Console::Write(S”\t{0}”, Mi Enumerador→Current);

Console::Write Line ? (); }

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

};

int main() { Stack __gc *Mi Pila ? = new Stack();

Mi Pila→Push(S”Hola”);

Mi Pila→Push(S”Mundo”);

Mi Pila→Push(S”!”);

// Despliega las propiedades y valores de los pila.

Console::Write Line(S”Mi Pila”);

Console::Write Line(S”\tCount: {0}”, __box(Mi Pila→Count)); Console::Write(S”\tValores:”);

Ejemplo Stack::Imprime(Mi Pila);

system(“pause”);

return 0;

2.3 Colas Definicion

Una cola es una estructura de datos, caracterizada por ser una secuencia de elementos en la que la operación de inserción push se realiza por un extremo y la operación de extracción pop por el otro. También se le llama estructura FIFO (del inglés First In First Out), debido a que el primer elemento en entrar será también el primero en salir.

El tipo cola representa la idea que tenemos de cola en la vida real. La cola para subir al autobús está compuesta de elementos (personas), que dispone de dos extremos comienzo y fin. Por el comienzo se extraerá un elemento cuando haya comprado el billete para su viaje, y si llega una nueva persona con intención de

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

usar el autobús, tendrá que colocarse al final y esperar que todos los elementos situados antes que él abandonen la cola.

2.3.2 Tipos 2.3.2.1 Colas Simples

Se inserta por un sitio y se saca por otro, en el caso de la cola simple seinserta por el final y se saca por el principio. Para gestionar este tipo de colahay que recordar siempre cual es el siguiente elemento que se va a leer y cuales el último elemento que se ha introducido.910973175137

2.3.2.2 Colas Circulares

En las colas circulares se considera que después del último elemento seaccede de nuevo al primero. De esta forma se reutilizan las posicionesextraídas, el final de la cola es a su vez el principio, creándose un circuitocerrado.5 5 54 4 4 43 3 3 32 2 2 21 1 8Lo que se ha hecho es insertar (5), sacar (1), e insertar (8).Se sabrá que una tabla está llena cuando “rear” y “front” estén en unaposición de diferencia.El teclado de ordenador se comporta exactamente como una colacircular.Para implementar las colas circulares mediante listas enlazadas se poneen el tipo T_Lista los punteros front y rear.

2.3.2.3 Colas Dobles

Esta estructura es una cola bidimensional en que las inserciones y eliminaciones se pueden realizar en cualquiera de los dos extremos de la bicola. Gráficamente representamos una bicola de la siguiente manera:

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Existen dos variantes de la doble cola:

Doble cola de entrada restringida. Doble cola de salida restringida.

La primer variante sólo acepta inserciones al final de la cola, y la segunda acepta eliminaciones sólo al frente de la cola

ALGORITMOS DE ENTRADA RESTRINGIDA

Algoritmo de Inicialización

F < -- 1A <-- 0

Algoritmo para Insertar

Si A=máximo entonces mensaje (overflow)en caso contrario A <--A+1 cola[A]<-- valor

Algoritmo para Extraer

Si F&gtA entonces mensaje (underflow)en caso contrario mensaje (frente/atrás)

si frente entonces x <-- cola[F] F <-- F+1en caso contrario x <-- cola[A] A <-- A-1

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

ALGORITMOS DE SALIDA RESTRINGIDA

Algoritmo de Inicialización

F <--1A <-- 0

Algoritmo para Insertar

Si F&gtA entonces mensaje (overflow)en caso contrario mensaje (Frente/Atrás) si Frente entonces

cola[F] <--valor en caso contrario

A <-- A+1cola[A] <--valor

Algoritmo para Extraer

Si F=0 entonces mensaje (underflow)en caso contrario x <--cola[F] F <-- F+1

2.3.3 Operaciones con Colas

    Como se mencionó en el tema anterior una cola es una coleccion ordenada de elementos a partir de la cual se pueden eliminar elementos de un extremo

(llamado frente de la cola) y en la cual tambien se pueden agregar elementos en el otro extremo(llamado parte posterior de la cola).

En la siguiente figura se representa una cola que tiene 3 elementos A,B y C. A es el elemento del frente de la cola. C es el elemento de la parte posterior.

En el ejemplo se ha eliminado un elemento de la cola. Pues como los elementos pueden ser retirados

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

unicamente del frente de la cola, a menudo se utilizan para simular situaciones del mundo real. En el ejemplo b) se ha estraido el primer elemento de la cola, el elemento A.

En el ejemplo c se han agregado los elementos D y E estos deben agregarse por la parte posterior de la cola.  

    Puesto que se ha insertado D primero que E, este sera retirado tambien primero. El primer elemento que se adiciona a una cola es el primer elemento que sera retirado.     Por esta razon una cola es algunas veces denominada como una lista de tipo PEPS(primero que entra, primero que sale, en ingles FIFO), en contra posicion de la pila , que es de tipo UEPS (Ultimo que entra, primero que sale, en ingles LIFO).     Existe muchos ejemplos de colas en el mundo real, como una linea de espera para tomar un autobus, un grupo de tarjetas que esperan ser leidas por umn lector optico, etc. 

2.3.4 Clases para Implementacion de Colas

Este programa establece una diferenciación en la urgencia de los mensajes enviados a través de Internet, a traves de un sistema de clasificación de los mismos.

La generación de la categoría de urgencias de un mensaje es responsabilidad del emisor e involucra un costo dependiente de la diferenciación.

Un mensaje consiste de un texto, cuya longitud máxima es de 256 caracteres, y un código de urgencia de 3 colores (Blanco < Azul < Rojo).

El servidor encargado de la emisión de mensajes lo hace en estricto orden de urgencias y para clasificarlos utiliza una cola de Mensajes y 3 colas de color. Blanca, Azul y Rojas.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

3 Listas enlazadas 3.1 Listas Enlazadas Simples

Una lista de enlace simple es una lista enlazada de nodos, donde cada nodo tiene un único campo de enlace. Una variable de referencia contiene una referencia al primer nodo, cada nodo (excepto el último) enlaza con el nodo siguiente, y el enlace del último nodo contiene NULL  para indicar el final de la lista. Aunque normalmente a la variable de referencia se la suele llamar top,

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

usted puede elegir el nombre que quiera. La siguiente figura presenta una lista de enlace simple de tres nodos, donde top referencia al nodo A, A conecta con B y B conecta con C y C es el nodo final:

 :

Listas simples enlazadas [editar]

La lista enlazada básica es la lista enlazada simple la cual tiene un enlace por nodo. Este enlace apunta al siguiente nodo en la lista, o al valor NULL o a la lista vacía, si es el último nodo.

Una lista enlazada simple contiene dos valores: el valor actual del nodo y un enlace al siguiente nodo

3.1.2 Listas Enlazadas Dobles Listas enlazadas circulares [editar]

En una lista enlazada circular, el primer y el último nodo están unidos juntos. Esto se puede hacer tanto para listas enlazadas simples como para las doblemente enlazadas. Para recorrer un lista enlazada circular podemos empezar por cualquier nodo y seguir la lista en cualquier dirección hasta que se regrese hasta el nodo original. Desde otro punto de vista, las listas enlazadas circulares pueden ser vistas como listas sin comienzo ni fin. Este tipo de listas es el más usado para dirigir buffers para “ingerir” datos, y para visitar todos los nodos de una lista a partir de uno dado.

Una lista enlazada circular que contiene tres valores enteros

3.1.3 Listas Enlazadas Circulares

Cada nodo tiene un enlace, similar al de las listas enlazadas simples, excepto que el siguiente nodo del último apunta al primero. Como en una lista enlazada simple, los nuevos nodos pueden ser solo eficientemente insertados después de uno que ya tengamos referenciado. Por esta razón, es usual quedarse con una

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

referencia solamente al último elemento en una lista enlazada circular simple, esto nos permite rápidas inserciones al principio, y también permite accesos al primer nodo desde el puntero del último nodo. 1

3.1.4 Listas Enlazadas Multilistas

3.1.5 Clases para Implementacion de Listas

Unidad 4 Estructuras no lineales 4.1 Arboles Definicion

En ciencias de la computación, un árbol es una estructura de datos ampliamente usada que emula la forma de un árbol (un conjunto de nodos conectados). Un nodo es la unidad sobre la que se construye el árbol y puede tener cero o mas nodos hijos conectados a él. Se dice que un nodo a es padre de un nodo b, si existe un enlace desde a hasta b (en ese caso, también decimos que b es hijo de a). Sólo puede haber un único nodo sin padres, que llamaremos raíz. Un nodo que no tiene hijos se conoce como hoja.

El árbol También se define como una estructura de datos no lineal. Esta estructura se usa principalmente para representar datos con una relación jerárquica entre sus elementos, como por ejemplo registros, árboles genealógicos y tablas de contenidos. Entre otros tenemos un tipo especial de de árbol que es, llamado árbol binario, que puede ser implementado fácilmente en la computadora.

4.1.2 Representacion en Memoria de Arboles

Representación en Memoria

Hay dos formas tradicionales de representar un árbol binario en memoria:

Por medio de datos tipo punteros también conocidos como variables dinámicas o listas.

Por medio de arreglos.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Sin embargo la más utilizada es la primera, puesto que es la más natural para tratar este tipo de estructuras.

Los nodos del árbol binario serán representados como registros que contendrán como mínimo tres campos. En un campo se almacenará la información del nodo. Los dos restantes se utilizarán para apuntar al subarbol izquierdo y derecho del subarbol en cuestión.

Cada nodo se representa gráficamente de la siguiente manera:

El algoritmo de creación de un árbol binario es el siguiente:

Procedimiento crear(q:nodo) inicio

mensaje("Rama izquierda?")lee(respuesta)si respuesta = "si" entonces

new(p)q(li) <-- nilcrear(p)

en caso contrarioq(li) <-- nil

mensaje("Rama derecha?")lee(respuesta)si respuesta="si" entonces

new(p)q(ld)<--pcrear(p)

en caso contrarioq(ld) <--nil

finINICIO

new(p)raiz<--pcrear(p)

FIN

4.1.2.1 Arboles Generales

ARBOLES GENERALES

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

1. INTRODUCCIÓN.

Hasta ahora las estructuras de datos que hemos estudiado eran de tipo lineal, o sea,existía una relación de anterior y siguiente entre los elementos que la componían(cada elemento tendrá uno anterior y otro posterior , salvo los casos de primero y último).Pues bien, aquí se va a estudiar una estructuración de los datos más compleja: los árboles.

Este tipo de estructura es usual incluso fuera del campo de la informática.El lector seguramente conoce casos como los árboles gramaticales para analizar oraciones,los árboles genealógicos ,representación de jerarquías,etc...La estructuración en árbol de los elementos es fundamental dentro del campo de la informática aplicándose en una amplia variedad de problemas como veremos más adelante.

En principio podemos considerar la estructura de árbol de manera intuitiva como una estructura jerárquica.Por tanto,para estructurar un conjunto de elementos e i

en árbol, deberemos escoger uno de ellos e1 al que llamaremos raíz del árbol.Del resto de los elementos se selecciona un subconjunto e2,...,ek

estableciendo una relación padre-hijo entre la raíz y cada uno de dichos elementos de manera que e1 es llamado el padre de e2,de e3,...ek y cada uno de ellos es llamado un hijo de e1.Iterativamente podemos realizar la misma operación para cada uno de estos elementos asignando a cada uno de ellos un número de 0 o más hijos hasta que no tengamos más elementos que insertar.El único elemento que no tiene padre es e1,la raíz del árbol.Por otro lado hay un conjunto de elementos que no tienen hijos aunque sí padre que son llamados hojas.Como hemos visto la relación de paternidad es una relación uno a muchos.

Para tratar esta estructura cambiaremos la notación:

Las listas tienen posiciones.Los árboles tienen nodos. Las listas tienen un elemento en cada posición.Los árboles tienen una

etiqueta en cada nodo (algunos autores distinguen entre árboles con y sin etiquetas.Un árbol sin etiquetas tiene sentido aunque en la inmensa mayoría de los problemas necesitaremos etiquetar los nodos. Es por ello por lo que a partir de ahora sólo haremos referencia a árboles etiquetados).

Usando esta notación,un árbol tiene uno y sólo un nodo raíz y uno o más nodos hoja.

Desde un punto de vista formal la estructura de datos árbol es un caso particular de grafo, más concretamente,en la teoría de grafos se denota de forma similar

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

como árbol dirigido. A pesar de ello,la definición formal más usual de árbol en ciencias de la computación es la recursiva:

El caso básico es un árbol con un único nodo.Lógicamente este nodo es a la vez raíz y hoja del árbol.

Para construir un nuevo árbol a partir de un nodo n r y k árboles A1 ,A2,...,Ak de raíces n1,n2,...,nk con N1,N2,...,Nk elementos cada uno establecemos una relación padre-hijo entre nr y cada una de las raíces de los k árboles.El árbol resultante de N=1 + N1 + ... + Nk nodos tiene como raíz el nodo nr, los nodos n1,n2,...,nk son los hijos de nr y el conjunto de nodos hoja está formado por la unión de los k conjuntos hojas iniciales. Además a cada uno de los Ai se les denota subárboles de la raíz.

Ejemplo: Consideremos el ejemplo de la siguiente figura.

Podemos observar que cada uno de los identificadores representa un nodo y la relación padre-hijo se señala con una línea.Los árboles normalmente se presentan en forma descendente y se interpretan de la siguiente forma:

E es la raíz del árbol. S1,S2,S3 son los hijos de E. S1,D1 componen un subárbol de la raíz. D1,T1,T2,T3,D3,S3 son las hojas del árbol. etc...

Además de los términos introducidos consideraremos la siguiente terminología:

1. Grado de salida o simplemente grado.Se denomina grado de un nodo al número de hijos que tiene.Así el grado de un nodo hoja es cero.En la figura anterior el nodo con etiqueta E tiene grado 3.

2. Caminos.Si n1,n2,...,nk es una sucesión de nodos en un árbol tal que ni es el padre de ni+1 para 1<=i<=k-1 ,entonces esta sucesión se llama un camino del nodo ni al nodo nk.La longitud de un camino es el número de nodos menos uno, que haya en el mismo.Existe un camino de longitud cero de cada nodo a sí mismo.Ejemplos sobre la figura anterior:

E,S2,D2,T3 es un camino de E a T3 ya que E es padre de S2,éste es padre de D2,etc.

S1,E,S2 no es un camino de S1 a S2 ya que S1 no es padre de E.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

3. Ancestros y descendientes.Si existe un camino,del nodo a al nodo b ,entonces a es un ancestro de b y b es un descendiente de a.En el ejemplo anterior los ancestros de D2 son D2,S2 y E y sus descendientes D2,T1,T2 y T3(cualquier nodo es a la vez ancestro y descendiente de sí mismo). Un ancestro o descendiente de un nodo,distinto de sí mismo,se llama un ancestro propio o descendiente propio respectivamente.Podemos definir en términos de ancestros y descendientes los conceptos de raíz,hoja y subárbol:

En un árbol,la raíz es el único nodo que no tiene ancestros propios.

Una hoja es un nodo sin descendientes propios. Un subárbol de un árbol es un nodo,junto con todos sus

descendientes.

Algunos autores prescinden de las definiciones de ancestro propio y descendiente propio asumiendo que un nodo no es ancestro ni descendiente de sí mismo.

4. Altura.La altura de un nodo en un árbol es la longitud del mayor de los caminos del nodo a cada hoja.La altura de un árbol es la altura de la raíz.Ejemplo: en la figura anterior la altura de S2 es 2 y la del árbol es 3.

5. Profundidad.La profundidad de un nodo es la longitud del único camino de la raíz a ese nodo.Ejemplo: en la figura anterior la profundidad de S2 es 1.

6. Niveles.Dado un árbol de altura h se definen los niveles 0...h de manera que el nivel i está compuesto por todos los nodos de profundidad i.

7. Orden de los nodos.Los hijos de un nodo usualmente están ordenados de izquierda a derecha.Si deseamos explícitamente ignorar el orden de los dos hijos, nos referiremos a un árbol como un árbol no-ordenado.

La ordenación izquierda-derecha de hermanos puede ser extendida para comparar cualesquiera dos nodos que no están relacionados por la relación ancestro-descendiente.La regla a usar es que si n1 y n2 son hermanos y n1 está a la izquierda de n2, entonces todos los descendientes de n1 están a la izquierda de todos los descendientes de n2.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

RECORRIDOS DE UN ÁRBOL.

En una estructura lineal resulta trivial establecer un criterio de movimiento por la misma para acceder a los elementos, pero en un árbol esa tarea no resulta tan simple.No obstante, existen distintos métodos útiles en que podemos sistemáticamente recorrer todos los nodos de un árbol.Los tres recorridos más importantes se denominan preorden,inorden y postorden aunque hay otros recorridos como es el recorrido por niveles.

Si consideramos el esquema general de un árbol tal como muestra la figura siguiente,los recorridos se definen como sigue:

8. El listado en preorden es: Si el árbol tiene un único elemento, dicho elemento es el

listado en preorden. Si el árbol tiene más de un elemento,es decir,una estructura

como muestra la figura 2,el listado en preorden es listar el nodo raíz seguido del listado en preorden de cada uno de los subárboles hijos de izquierda a derecha.

9. El listado en inorden es: Si el árbol tiene un único elemento,dicho elemento es el

listado en inorden. Si el árbol tiene una estructura como muestra la figura 2,el

listado en inorden es listar el subárbol A1 en inorden,y listar el nodo raíz seguido del listado en inorden de cada uno de los subárboles hijos de izquierda a derecha restantes.

10.El listado en postorden es: Si el árbol tiene un único elemento,dicho elemento es el

listado en postorden. Si el árbol tiene una estructura como muestra la figura 2,el

listado en postorden es listar en postorden cada uno de los subárboles hijos de izquierda a derecha seguidos por el nodo raíz.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

11.El listado por niveles es: desde i=0 hasta la altura h del árbol,listar de izquierda a derecha los elementos de profundidad i.Como podemos observar,un nodo n1 aparece antes que n2 en el listado por niveles si la profundidad de n1 es menor que la profundidad de n2 usando el orden de los nodos definido anteriormente para el caso en que tengan la misma profundidad.

Como ejemplo de listados veamos el resultado que se obtendría sobre el árbol A de la figura 3.

Los resultados de los listados de preorden,postorden e inorden son los siguientes:

12.Listado preorden.A=Ar=rAvAs=rvAuAwAs= rvuAwAs=rvuwAxAyAzAs= rvuwxAyAzAs=rvuwxyAzAs=rvuwxyzAs

=rvuwxyzsApAq=rvuwxyzspAq=rvuwxyzspq.13.Listado postorden.

A=Ar=AvAsr=AuAwvAsr= uAwvAsr=uAxAyAzwvAsr= uxAyAzwvAsr=uxyAzwvAsr=uxyzwvAsr= uxyzwvApAqsr=uxyzwvpAqsr=uxyzwvpqsr.

14.Listado inorden.A=Ar=AvrAs=AuvAwrAs= uvAwrAs=uvAxwAyAzrAs=uvxw AyAzrAs=uvxwyAzrAs=uvxwyzrAs= uvxwyzrApsAq=uvxwyzrpsAq=uvxwyzrpsq.

Por último,el listado por niveles de este árbol es el siguiente:r,v,s,u,w,p,q,x,y,z.

Finalmente es interesante conocer que un árbol no puede,en general,recuperarse con uno solo de sus recorridos.Por ejemplo:Dada la lista en inorden:vwyxzrtupsq,los árboles de la figura 4 tienen ese mismo recorrido en inorden.

2. UNA APLICACIÓN: ARBOLES DE EXPRESIÓN.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Una importante aplicación de los árboles en la informática es la representación de árboles sintácticos,es decir,árboles que contienen las derivaciones de una gramática necesarias para obtener una determinada frase de un lenguaje.

Podemos etiquetar los nodos de un árbol con operandos y operadores de manera que un árbol represente una expresión.Por ejemplo. en la figura 5 se representa un árbol con la expresión aritmética (x-y)*(z/t).

Para que un árbol represente una expresión,hay que tener en cuenta que:

Cualquier hoja está etiquetada con uno y sólo un operando. Cualquier nodo interior n está etiquetado por un operador.

En los árboles de expresión,la sucesión del preorden de etiquetas nos da lo que se conoce como la forma prefijo de una expresión, en la que el operador precede a su operando izquierdo y su operando derecho.En el ejemplo de la figura 5,el preorden de etiquetas del árbol es *-xy/zt .

Análogamente,la sucesión postorden de las etiquetas de un árbol expresión nos da lo que se conoce como la representación postfijo de una expresión.Así en el ejemplo,la expresión postfijo del árbol es xy-zt/*.

Finalmente,el inorden de una expresión en un árbol de expresión da la expresión infijo en sí misma,pero sin paréntesis.En el ejemplo,la sucesión inorden del árbol anterior es x-y*z/t.

3. EL TIPO DE DATO ABSTRACTO "ARBOL".

La estructura de árbol puede ser tratada como un tipo de dato abstracto.A continuación presentaremos varias operaciones sobre árboles y veremos como los algoritmos de árboles pueden diseñarse en términos de estas operaciones.Al igual que con otros TDA,existe una gran variedad de operaciones que pueden llevarse a cabo sobre árboles.

Como podremos observar,cuando se construye una instancia de este tipo,tiene al menos un elemento, es decir,hasta ahora no hemos hablado de la existencia de un árbol vacío .Realmente, según la definición que vimos,efectivamente el número mínimo de nodos de un árbol es 1.En las implementaciones usaremos un valor especial ARBOL_VACIO para el caso en que el árbol no contenga nodos,al igual que en listas existe el concepto de lista vacía.

De igual forma es necesario expresar en algunos casos que un nodo no existe para lo cual también usaremos otro valor especial NODO_NULO.Un ejemplo de

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

su uso puede ser cuando intentemos extraer el nodo hijo a la izquierda de un nodo hoja.

A continuación mostramos el conjunto de primitivas que nosotros consideraremos:

1. CREAR_RAIZ(u).Construye un nuevo nodo r con etiqueta u y sin hijos.Se devuelve el árbol con raíz r,es decir,un árbol con un único nodo.

2. DESTRUIR(T).Libera los recursos que mantienen el árbol T de forma que para volver a usarlo se debe de asignar un nuevo valor con la operación de creación.

3. PADRE(n,T).Esta función devuelve el padre del nodo n en el árbol T .Si n es la raíz ,que no tiene padre,devuelve NODO_NULO(un valor que será usado para indicar que hemos intentado salirnos del árbol).Como precondición n no es NODO_NULO (por tanto T no es vacío)..

4. HIJO_IZQDA(n,T).Devuelve el descendente más a la izquierda en el siguiente nivel del nodo n en el árbol T, y devuelve NODO_NULO si n no tiene hijo a la izquierda.Como precondición n no es NODO_NULO.

5. HERMANO_DRCHA(n,T).Devuelve el descendiente a la derecha del nodo n en el árbol T ,definido para ser aquel nodo m con el mismo padre que n ,es decir, padre p,de tal manera que m cae inmediatamente a la derecha de n en la ordenación de los hijos de p (Por ejemplo,véase el árbol de la figura 6). Devuelve NODO_NULO si n no tiene hermano a la derecha.Como precondición n no es NODO_NULO.

6. ETIQUETA(n,T).Devuelve la etiqueta del nodo n en el árbol T (manejaremos árboles etiquetados,sin embargo no es obligatorio definir etiquetas para cada árbol).Como precondición n no es NODO_NULO.

7. REETIQUETA(e,n,T).Asigna una nueva etiqueta e al nodo n en el árbol T.Como precondición n no es NODO_NULO.

8. RAIZ(T).Devuelve el nodo que está en la raíz del árbol T o NODO_NULO si T es el árbol vacío.

9. INSERTAR_HIJO_IZQDA(n,Ti,T).Inserta el árbol Ti como hijo a la izquierda del nodo n que pertenece al árbol T.Como precondición n no es NODO_NULO y Ti no es el árbol vacío.

10. INSERTAR_HERMANO_DRCHA(n,Td,T).Inserta el árbol Td como hermano a la derecha del nodo n que pertenece al árbol T.Como precondición n no es NODO_NULO y Td no es el árbol vacío.

11.PODAR_HIJO_IZQDA(n,T).Devuelve el subárbol con raíz hijo a la izquierda de n del árbol T el cual se ve privado de estos nodos.Como precondición n no es NODO_NULO.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

12.PODAR_HERMANO_DRCHA(n,T).Devuelve el subárbol con raíz hermano a la derecha de n del árbol T el cual se ve privado de estos nodos.Como precondición n no es NODO_NULO.

A continuación veremos cómo implementar el TDA árbol y posteriormente implementaremos los algoritmos de recorrido:PREORDEN,POSTORDEN,INORDEN.

IMPLEMENTACIÓN DE ÁRBOLES.

UNA IMPLEMENTACIÓN MATRICIAL

Sea A un árbol en el cual los nodos se etiquetan 0,1,2,...,n-1,es decir,cada nodo contiene un campo de información que contendrá estos valores.La representación más simple de A que soporta la operación PADRE es una matriz lineal P en la cual el valor de P[i] es un valor o un cursor al padre del nodo i.La raíz de A puede distinguirse dándole un valor nulo o un valor a él mismo como padre.Por ejemplo.,podemos usar un esquema de cursores donde P[i]=j si el nodo j es el padre del nodo i,y P[i]=-1 (suponemos que NODO_NULO=-1) si el nodo i es la raíz.La definición del tipo sería:

#define MAXNODOS 100 /*Por ejemplo*/#define NODO_NULO -1

typedef int nodo; /*Indica una casilla de la matriz*/typedef int *ARBOL;

Esta representación usa la propiedad de los árboles de que cada nodo tiene un único padre.Con esta representación el padre de un nodo puede encontrarse en tiempo constante.Un camino hacia arriba en el árbol puede seguirse atravesando el árbol en tiempo proporcional al número de nodos en el camino.Podemos soportar también el operador ETIQUETA añadiendo otra matriz L ,tal que L[i] es la etiqueta del nodo i ,o haciendo que los elementos de la matriz A sean registros consistiendo en un entero(cursor)y una etiqueta.EJEMPLO:Véase el árbol de la figura 7:

La representación de padre por cursores no facilita las operaciones que requieren información de hijos.Dado un nodo n ,es costoso determinar los hijos de n o la altura de n.Además,la representación por cursores del padre no especifica el orden de los hijos de un nodo.Por tanto,operaciones como HIJO_IZQDA y HERMANO_DRCHA no están bien definidas.Podríamos imponer

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

un orden artificial,por ejemplo,numerando los hijos de cada nodo después de numerar el padre,y numerar los hijos en orden creciente de izquierda a derecha.

Nota:Téngase en cuenta que aunque esta implementación no parece muy adecuada, es posible ampliarla con la utilización de nuevos campos de cursores.Por ejemplo:Podemos añadir dos matrices adicionales para almacenar para cada nodo tanto el hijo a la izquierda como el hermano a la derecha.

IMPLEMENTACIÓN DE ÁRBOLES POR LISTAS DE HIJOS

Una forma útil e importante de representar árboles es formar para cada nodo una lista de sus hijos.Las listas pueden representarse por cualquier método,pero como el número de hijos que cada nodo puede tener puede ser variable,las representaciones por listas enlazadas son las más apropiadas.La figura 8 sugiere como puede representarse el árbol del ejemplo de la figura 7:

Hay una matriz de celdas de cabecera indexadas por nodos ,que suponemos numerados 0,1,2,...,n-1. Cada punto de cabecera apunta a una lista enlazada de elementos que son nodos.Los elementos sobre una lista encabezada por cabecera[i] son los hijos de i(por ejemplo, 9 y 4 son los hijos de 8).Si desarrollamos la estructura de datos que necesitamos en términos de un tipo de dato abstracto tLista (de nodos) y damos una implementación particular de listas,puede verse como las abstracciones encajan.

#include /*Definidas apropiadamente*/#define MAXNODOS 100 /*Por ejemplo*/#define NODO_NULO -1

typedef int nodo; typedef struct {

tLista cabecera[MAXNODOS];tEtiqueta etiquetas[MAXNODOS];nodo raiz;

}ARBOL;

Suponemos que la raíz de cada árbol está almacenada explícitamente en el campo raíz.El -1 en el campo raíz se usa para representar el árbol nulo o vacío.La siguiente función muestra el código para la operación HIJO_IZQDA:

nodo HIJO_IZQDA(nodo n,ARBOL T){ tLista L;

L=T.cabecera[n];

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

if(PRIMERO(L)==FIN(L)) return NODO_NULO; /*No tiene hijos*/ else return RECUPERA(PRIMERO(L),L); /*Recupera el primero(izqda)*/}

Las demás operaciones son también fáciles de implementar utilizando la anterior estructura para el tipo de dato y usando las primitivas del TDA Lista.

Nota:Las funciones PRIMERO,FIN y RECUPERA usadas en el ejemplo anterior pertenecen al TDA Lista anteriormente estudiado.

IMPLEMENTACIÓN DE ÁRBOLES BASADA EN CELDAS ENLAZADAS

Al igual que ocurre en los TDA estudiados (Listas,Pilas o Colas), un nodo puede ser declarado de forma que la estructura del árbol pueda ir en aumento mediante la obtención de memoria de forma dinámica,haciendo una petición de memoria adicional cada vez que se quiere crear un nuevo nodo.

#define ARBOL_VACIO NULL#define NODO_NULO NULL

typedef int tEtiqueta /*Algún tipo adecuado*/typedef struct tipocelda{ struct tipocelda *padre,*hizqda,*herdrchaAr; tEtiqueta etiqueta; }*nodo;typedef nodo tArbol;

Observemos que bajo esta implementación cada nodo de un árbol contiene 3 punteros: padre que apunta al padre,hizqda que apunta al hijo izquierdo y herdrcha que apunta al hermano a la derecha del nodo.Para esta implementación de árbol vamos a presentar las funciones primitivas de las que hablábamos al principio.Suponemos que para referenciar el nodo i la variable puntero apuntará a ese nodo.Suponemos también unas variables de tipo nodo y que la variable T de tipo árbol apunta a la raíz del árbol.

nodo PadreAr(nodo n,tArbol T){ return n->padre;}

nodo HizqdaAr(nodo n,tArbol T){ return n->hizqda;

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

}

nodo HerdrchaAr(nodo n,tArbol T){ return n->herdrchaAr;}

tEtiqueta EtiquetaAr(nodo n,tArbol T){ return n->etiqueta;}

void ReEtiquetaAr(tEtiqueta e,nodo n,tArbol T){ n->etiqueta=e;}

nodo RaizAr(tArbol T){ return T;}

tArbol Crea0(tEtiqueta et){ tArbol raiz; raiz=(tArbol)malloc (sizeof(struct tipocelda)); if (!raiz){ error("Memoria Insuficiente."); } raiz->padre=NULL; raiz->hizqda=NULL; raiz->etiqueta=et;

return raiz;}

void Destruir(tArbol T){ if(T){ destruir(T->hizqda); destruir(T->herdrcha); free(T); }}

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

void Insertar_hijo_izqda(nodo n,tArbol Ti,tArbol T){ Ti->herdrcha=n->hizqda; Ti->padre=n; n->hizqda=Ti;}

void Insertar_hermano_drcha(nodo n,tArbol Td,tArbol T){ if(n==raizAr(T)){ error("Memoria Insuficiente."); } Td->herdrcha=n->herdrcha; Td->padre=n->padre; n->herdrcha=Td;}

tArbol Podar_hijo_izqda(nodo n,tArbol T){ tArbol Taux; Taux=n->hizqda; if(Taux!=ARBOL_VACIO){ n->hizqda=Taux->herdrcha; Taux->padre=NODO_NULO; Taux->herdrcha=NODO_NULO; } return Taux;}

tArbol Podar_hermano_drcha(nodo n,tArbol T){ tArbol Taux; Taux=n->herdrcha; if(Taux!=ARBOL_VACIO){ n->herdrcha=Taux->herdrcha; Taux->padre=NODO_NULO; Taux->herdrcha=NODO_NULO; }

return Taux;

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

}

Como vemos hemos implementado creaRaiz de manera que el árbol devuelto es un único nodo.Es posible construir en C un procedimiento con un número variable de parámetros:

El primero de los parámetros una etiqueta para el nodo raíz. Los restantes parámetros de tipo tArbol que se insertarán como

subárboles(hijos) del nodo raíz.

Los podemos realizar mediante la implementación de un número de parámetros indeterminado y haciendo uso del tipo va_list que podemos encontrar en el fichero cabecera stdarg.h.El procedimiento podría ser el siguiente:

tArbol CreaRaiz(tEtiqueta et,tArbol T1,...,tArbol Tn,NULL){ va_list ap; nodo n,aux,raiz;

/*Reservamos memoria para el nodo raiz*/ raiz=(nodo)malloc(sizeof(struct tipocelda)); if(!raiz){ error("Memoria Insuficiente."); } /*Inicializamos el nodo raiz*/ raiz->padre=NULL; raiz->hizqda=NULL; raiz->herdrcha=NULL; raiz->etiqueta=et; /*Un bucle para insertar los subarboles*/ va_start(ap,et); /*Inicio de argumentos*/ for(;;){ n=(nodo)va_arg(ap,nodo); if(n==NULL)break; /*No quedan mas hijos*/ if(raiz->hizqda)aux->herdrcha=n; else raiz->hizqda=n; aux=n; aux->herdrcha=NULL; aux->padre=raiz; } va_end(ap); /*Final de argumentos*/ return(tArbol)raiz;}

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

La llamada a la función tendría como parámetros una etiqueta para el nodo raíz del árbol resultante y una lista de nodos que podría ser vacía en cuyo caso el árbol que resulta tiene un único nodo:su raíz con etiqueta et. Por último,después de dicha lista,es necesario un parámetro adicional(NULL) que indica el final de la lista tras cuya lectura el procedimiento dejaría de añadir más hijos al nodo raíz que se está construyendo.

IMPLEMENTACIÓN DE LOS RECORRIDOS DE UN ÁRBOL

Recordemos que los recorridos de un árbol pueden ser de una forma directa en Preorden, Inorden y Postorden.A continuación veremos la implementación de estos tres recorridos. Así mismo,veremos un procedimiento de lectura de un árbol en preorden.

PREORDEN

1. Visitar la raíz.2. Recorrer el subárbol más a la izquierda en preorden.3. Recorrer el subárbol de la derecha en preorden.

Vamos a escribir dos procedimientos uno recursivo y otro no recursivo que toman un árbol y listan las etiquetas de sus nodos en preorden.Supongamos que existen los tipos nodo y tArbol con etiquetas del tipo tEtiqueta definidos anteriormente en la implementación por punteros.El siguiente procedimiento muestra un procedimiento recursivo que , dado el nodo n,lista las etiquetas en preorden del subárbol con raíz en n.

void PreordenArbol(nodo n,tArbol T){ Escribir(etiquetaAr(n,T)); for(n=hizqdaAr(n,T);n!=NODO_NULO;n=herdrchaAr(n,T)) PreordenArbol(n,T);}

En esta función hemos supuesto que existe una rutina Escribir que tiene como parámetro de entrada un valor de tipo tEtiqueta que se encarga de imprimir en la salida estándar.Por ejemplo,si hemos realizado typedef int tEtiqueta la función podría ser la siguiente:

void Escribir(tEtiqueta et){ fprintf(stdout,"%d",(int)et);}

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Por otro lado,en los programas C hemos usado el operador de desigualdad entre un dato de tipo nodo y la constante ARBOL_VACIO.Para hacerlo más independiente de la impementación sería conveniente programar una función que podríamos llamar Arbol_Vacio que se añadiría como una nueva primitiva que nos devuelve si el subárbol que cuelga del nodo es un árbol vacío.

Para el procedimiento no recursivo,usaremos una pila para encontrar el camino alrededor del árbol.El tipo PILA es realmente pila de nodos,es decir,pila de posiciones de nodos. La idea básica subyacente al algoritmo es que cuando estamos en la posición p,la pila alojará el camino desde la raíz a p,con la raíz en el fondo de la pila y el nodo p a la cabeza.El programa tiene dos modos de operar.En el primer modo desciende por el camino más a la izquierda en el árbol,escribiendo y apilando los nodos a lo largo del camino,hasta que encuentra una hoja.A continuación el programa entra en el segundo modo de operación en el cual vuelve hacia atrás por el camino apilado en la pila,extrayendo los nodos de la pila hasta que se encuentra un nodo en el camino con un hermano a la derecha.Entonces el programa vuelve al primer modo de operación,comenzando el descenso desde el inexplorado hermano de la derecha.El programa comienza en modo uno en la raíz y termina cuando la pila está vacía.

void PreordenArbol(tArbol T){ pila P; /*Pila de posiciones:tElemento de la pila es el tipo nodo*/ nodo m; P=CREAR(); /*Funcion de creacion del TDA PILA*/

m=raizAr(T); do{ if(m!=NODO_NULO){ Escribir(etiquetaAr(n,T)); PUSH(m,P); m=hizqdaAr(m,T); } else if(!VACIA(P)){ m=herdrchaAr(TOPE(P),T); POP(P); } }while(!VACIA(P));

DESTRUIR(P); /*Funcion del TDA PILA*/}

INORDEN

1. Recorrer el subárbol más a la izquierda en inorden.

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

2. Visitar la raíz.3. Recorrer el subárbol del siguiente hijo a la derecha en inorden.

Vamos a escribir un procedimiento recursivo para listar las etiquetas de sus nodos en inorden.

void InordenArbol(nodo n,tArbol T){ nodo c;

c=hizqdaAr(n,T); if(c!=NODO_NULO){ InordenArbol(c,T); Escribir(etiquetaAr(n,T)); for(c=herdrchaAr(c,T);c!=NODO_NULO;c=herdrchaAr(c,T)) InordenArbol(c,T); } else Escribir(etiquetaAr(n,T));}

POSTORDEN

1. Recorrer el subárbol más a la izquierda en postorden.2. Recorrer el subárbol de la derecha en postorden.3. Visitar la raíz.

El procedimiento recursivo para listar las etiquetas de sus nodos en postorden es el siguiente:

void PostordenArbol(nodo n,tArbol T){ nodo c;

for(c=hizqdaAr(n,T);c!=NODO_NULO;c=herdrchaAr(c,T)) PostordenArbol(c,T);

Escribir(etiquetaAr(n,T));}

LECTURA

A continuación veremos un procedimiento que nos realizará la lectura de los nodos de un árbol introduciéndolos en preorden.La función implementada se

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

llama Lectura aunque se listan dos funciones(la rutina Lectura2 es una función auxiliar que es usada por la primera).

void Lectura2(nodo n,tArbol T){ tEtiqueta etHijo,etHermano; tArbol Hijo,Hermano;

fprintf(stdout,"Introduce hijo_izqda de: "); Escribir(etiquetaAr(n,T)); Leer(&etHijo);

if(comparar(etHijo,FINAL)){ Hijo=creaRaiz(etHijo); insertar_hijo_izqda(n,Hijo,T); Lectura2(hizqdaAr(n,T),T); }

fprintf(stdout,"Introduce her_drcha de: "); Escribir(etiquetaAr(n,T)); Leer(&etHermano);

if(comparar(etHermano,FINAL)){ Hermano=creaRaiz(etHermano); insertar_hermano_drcha(n,Hermano,T); Lectura2(herdrchaAr(n,T),T); }}

tArbol Lectura(){ tArbol T; tEtiqueta et;

fprintf(stdout,"En caso de que no exista el hijo_izqdo o el" "hermano_derecho introducir el valor: "); Escribir(FINAL); /*FINAL actua de centinela*/ fprintf(stdout,"\nIntroduce la raiz del arbol: "); Leer(&et); T=creaRaiz(et); Lectura2(raizAr(T),T);}

Es interesante observar 5 puntos en esta rutina:

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Hemos supuesto que existe una función Leer que tiene como parámetro de entrada un puntero a una zona de memoria que almacena un valor de tipo tEtiqueta,y que sirve para leer de la entrada estándar un dato de ese tipo y almacenarlo en dicha zona de memoria.

Existe una variable FINAL que contiene un valor para la etiqueta que "no es legal" para indicar la inexistencia de un hijo a la izquierda y/o de un hermano a la derecha.

Suponemos que existe una función comparar que tiene como parámetros de entrada dos variables de tipo tEtiqueta y que devuelve un valor entero distinto de 0 en caso de que las variables sean distintas según el criterio implementado en la función.

Las sentencias insertar_hijo_izqda(...);Lectura2(...);no son intercambiables,es decir,si hubieramos programado esas sentencias en otro orden (Lectura2(...);insertar_hijo_izqda(...);) la función de lectura no funcionaría correctamente.La comprobación de que esta afirmación es correcta se deja como ejercicio al lector.

En la segunda sentencia if ocurre una situación similar al punto anterior. Se puede completar la rutina de lectura para que prescinda de la lectura

de un posible hermano a la derecha de la raíz simplemente preguntándonos si n es la raíz del árbol T.

4.1.2.2 Arboles Binarios

Árboles binarios

Definición 10   Un árbol binario es una estructura de datos de tipo árbol en donde cada uno de los nodos del árbol puede tener 0, 1, ó 2 subárboles llamados de acuerdo a su caso como:

Si el nodo raíz tiene 0 relaciones se llama hoja. Si el nodo raíz tiene 1 relación a la izquierda, el segundo elemento de la

relación es el subárbol izquierdo. Si el nodo raíz tiene 1 relación a la derecha, el segundo elemento de la

relación es el subárbol derecho.

La figura 25 muestra algunas configuraciones de grafos que sí son árboles binarios, y la figura 26 muestra algnas configuraciones de grafos que no son árboles binarios.

Figura 25: Grafos que son estructuras tipo árbol binario

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

Figura 26: Grafos que no son árboles binarios

Vamos a dar una lista de teérminos que se usan frecuentemente cuando se trabaja con árboles:

Si A es la raíz de un árbol y B es la raíz de su subárbol izquierdo (o derecho), se dice que A es el padre de B y se dice que B es el hijo izquierdo (o derecho) de A.

Un nodo que no tiene hijos se denomina hoja El nodo a es antecesor del nodo b (y recíprocamente el nodo b es

descendiente del nodo a), si a es el padre de b o el padre de algún ancestro de b.

Un nodo b es un descendiente izquierdo del nodo a, si b es el hijo izquierdo de a o un descendiente del hijo izquierdo de a. Un descendiente derecho se define de la misma forma.

Dos nodos son hermanos si son hijos izquierdo y derecho del mismo padre.

Otros términos relacionados con árboles, tienen que ver con su funcinoamiento y topología:

Si cada nodo que NO es una hoja tiene un subárbol izquierdo y un subárbol derecho, entonces se trata de un árbol binario completo.

El nivel de un nodo es el número de aristas que se deben recorrer para llegar desde ese nodo al nodo raíz. De manera que el nivel del nodo raíz es 0, y el nivel de cualquier otro nodo es el nivel del padre más uno.

La profundidad de un nodo es el máximo nivel de cualquier hoja en el árbol.

Si un árbol binario tiene nodos en el nivel , el máximo número de nodos en el nivel es . Dado que un árbol binario sólo tiene un nodo en el nivel 0, puede contener un máximo de nodos en el nivel . Un árbol binario completo de profundidad es el árbol que contiene exactamente nodos en cada nivel entre 0 y . La cantidad total de nodos en un árbol binario completo de profundidad , es igual a la suma de nodos en cada nivel entre 0 y , por tanto:

Usando inducción matemática se puede demostrar que . Dado que todas las hojas en este árbol están en el nivel , el árbol contiene hojas y, por tanto, nodos que no son hojas.

Si conocemos el número total de nodos en un árbol binario completo, podemos calcular su profundidad , a partir de la expresión . Así sabemos que la profundidad es igual a 1 menos que el número de veces que 2 debe ser

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

multiplicado por sí mismo para llegar a . Es decir, que en un árbol binario completo,

Definición 11   Un árbol binario es un árbol binario casi completo si: 1. Cualquier nodo a un nivel menor que tiene 2 hijos 2. Para cualquier nodo en el árbol con un descendiente derecho en el nivel

debe tener un hijo izquierdo y cada descendiente izquierdo de : o es una hoja en el nivel ó o tiene dos hijos

Figura 27: Comparación de un árbol binario y un árbol binario casi completo. El árbol mostrado en (A) descumple la regla 2 de los árboles binarios casi completos.

Los nodos en un árbol binario (completo, casi completo o incompleto) se pueden enumerar del siguiente modo. Al nodo raíz le corresponde el número 1, al hijo izquierdo le corresponde el doble del número asignado al padre y al hijo derecho le corresponde el doble más 1 del número asignado al padre.

4.1.3 Recorridos en Arbol Binario Preorden

DEFINICIÓN DE ARBOL BINARIOUn ÁRBOL BINARIO es un conjunto finito de elementos que o está vacio o está dividido en tres subconjuntos  desarticulados. El primer subconjunto contiene un solo elemento llamado RAÍZ del árbol. Los otros dos son en sí mismos árboles binarios, llamados subárboles izquierdo y derecho del árbol original. Un subárbol izquierdo o derecho puede estar vacio. 

En  la  figura  se muestra como dibujar un árbol. Esté árbol consiste en 9 nodos y tiene a A como raíz. Su subárbol izquierdo tiene a B como raíz y su subárbol derecho a C. Esto queda señalado por las dos ramas que salen de A; hacia B a la izquierda y hacia C. La ausencia de ramas indica que es un subárbol vacio. 

PROPIEDADES DE LOS ÁRBOLES BINARIOS1. El máximo número de registros en un nivel i cualquiera es 2^(i-1).   2. Para un árbol binario de altura K el máximo número de registros es 2^(K)-1     Árbol lleno: es un árbol de altura K que tiene 2^(K)-1 nodos.  3. sea No = número de hojas del árbol 

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

         N2 =  número de nodos con grado 2.           síempre se cumplirá: No = N2 + 1 

REPRESENTACIÓN DE ÁRBOLES BINARIOS1. En un vector:

   1       2      3       4       5       6       7      8       9       0      1       2       3       4       5

ABICDJKEFGHLMNO

NIVEL |     NIVEL   |             NIVEL            |                             NIVEL                               |    1             2                        3                                                4

Al nivel 1 le corresponde la posición 1 del vector; al nivel 2 le corresponden las siguientes dos posiciones del  vector, ya que el maximo número de nodos en el nivel 2 es dos; al nivel tres le corresponden las siguientes 4 posiciones, ya que   el  máximo  número  de  nodos del nivel 3 es cuatro, y así sucesivamente.

Los nodos en cada nivel se llenan de izquierda a derecha. A cada nodo le carresponderá una posición fija del vector. 

Propiedades de la representación de un árbol binario en un vector: 

Para un nodo en la posición i del vector: 

a. Su padre se halla en la posición i/2 del vector( i > 1).   b. Su hijo izquierdo se halla en la posición 2*i.  c. Su hijo derecho se halla en la posición 2*i + 1. Árbol completo:

Es un árbol binario tal que al representarlo en un vector, utiliza efectivamente todas las posiciones del  vector.  Todo  árbol binario lleno es completo, lo contrario no siempre se cumple 

2. Como listas ligadas:

Siempre que se desee representar un objeto como lista ligada, lo primero que se debe hacer es configurar el nodo.     

LD Liga derecha

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

iga izquierda

ato

LI(X)               X                 LD(X) 

LI(X): Apunta hacia el nodo que es un hijo izquierdo de x.  LD(X): Apunta hacia el nodo que es un hijo derecho de x. 

Con esta representación se usan los nodos que efectivamente se necesitan. Con esta representación podremos  conocer fácil y eficientemente los hijos de cada nodo, ya que los campos de liga izquierda y liga derecha apuntan hacia los nodos que los representan. Si la aplicación que se desea implementar, manejando árboles, requiere permanentemente conocer al padre de un nodo, entonces se incluye un cuarto campo llamado Liga Al Padre. La configuración queda así:     

Liga izquierda

Dato

Liga derecha

Liga al padre

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

RECORRIDOS SOBRE ÁRBOLES BINARIOSExisten tres formas recursivas muy fáciles de recorrer  un árbol binario:  Recorridos Preorden, Inorden y posorden: 

PREORDEN:

a) Visitar la raíz del primer árbol.  b) Recorrer en preorden el árbol formado por subárboles del primer árbol,en caso de que exista.  c) Recorrer en preorden el árbol formado por los árboles restantes, en caso de que existan. Algoritmo de recorrido en preorden  procedure preorden(R)       if R <> 0 then            write (dato(R))            preorden(li (R))            preorden(ld (R))       end(if)  end (procedure) POSORDEN: a) Recorrer posorden el árbol formado por los subárboles del primer árbol, en caso de que lo haya.  b) Recorrer posorden el árbol formado por los árboles restantes, en caso de que existan.  c) Visitar la raíz del primer árbol. Ahora veremos como quedan los recorridos: 

INORDEN  BDEFCAIJKHGRPQMNOL 

POSORDEN FEDCBKJIHRQPONMLGA 

PREORDEN  ABCDEFGHIJKLMPRQNO 

4.1.3.2 Recorridos en Arbol Binario Inorden

4.1.3.3 Recorridos en ArbolBinario Posorden 4.1.4 Balanceo Arboles Binarios 4.1.5 Clases para Implementacion Arboles 4.2 Grafos Definicion

MATERIA: ESTRUCTURA DE DATOSLI. MA. DE LA LUZ AYAR MARTINEZ

4.2.2 Tipos de Grafos 4.2.3 Representacion de Grafos en Memoria 4.2.4 Clases para Implementacion de Grafos