Estructura de Datos y Arreglos en POO (Agosto-2011)
Contenido INTRODUCCIÓN ....................................................................................................................................... - 1 COMPORTAMIENTO DE UN ARREGLO ...................................................................................................... - 1 ARREGLOS COMO OBJETOS ..................................................................................................................... - 2 METHODS ............................................................................................................................................... - 3 PROPERTIES ............................................................................................................................................. - 4 EJEMPLO DE USO DE UN OBJETO DEL TIPO ARRAY .............................................................................................. - 4 -
ALTERNATIVA DE COMPORTAMIENTO OBJETOS DEL TIPO ARRAYLIST ..................................................... - 5 CONSTRUCTORS ........................................................................................................................................ - 6 METHODS ............................................................................................................................................... - 6 PROPERTIES ............................................................................................................................................. - 7 EJEMPLO DE USO DE UN OBJETO DEL TIPO ARRAYLIST ......................................................................................... - 8 -
RECOMENDACIÓN ................................................................................................................................... - 9 -
Estructura de Datos y Arreglos en POO
Introducción Con estas líneas voy a comentar la manera en que se implementan los arreglos en programación orientada a objetos. En principio es para mis alumnos de Estructura de Datos pero puede servir a quién tenga interés en cómo es esta cuestión. Desde el primer curso de programación los estudiantes de informática aprenden que existen tipos de datos (enteros, reales, caracteres, entre otros) así como las estructuras de control para implementar algoritmos que resuelvan un problema en particular. Luego llegan los "arreglos", en algunos casos conocidos como vectores (los de una dimensión) y matrices (cuando de dos dimensiones se trata). Por supuesto, en POO - Programación Orientada a Objetos también se utilizan estos conceptos pero desde el punto de vista del comportamiento, como debe ser si de OOP estamos hablando.
Comportamiento de un arreglo Los arreglos surgen como la necesidad de manipular en un algoritmo una colección de valores del mismo tipo utilizando una manera simple para poder acceder a cada uno de esos valores. El tipo de dato abstracto arreglo indica justamente eso; se trata de una colección de elementos homogénea (o sea del mismo tipo) a los que se tiene acceso por medio de uno o más índices. Con lo que nos queda claro que el comportamiento de un arreglo, es simplemente eso acceder a los elementos que están dentro del arreglo indicando su posición o índice. Este comportamiento, es básico; lo mínimo que se puede hacer con un arreglo y justamente es el comportamiento que los lenguajes de programación (cualquier modalidad) nos brindan. Cuando se desarrollan productos de software, hace falta añadir funcionalidad. Por ejemplo los matemáticos quieren que se pueda sumar los valores de un arreglo que contiene números, o calcular el promedio y otras cosas que se les ocurre; ni hablar cuando se trabaja con arreglos de dos dimensiones (matrices) donde se pide la realizaciones de operaciones matemáticas como la suma o producto de matrices, o la determinación de diagonales entre otros requerimientos. También surgen requerimientos como ordenar el contenido de un arreglo y ahí es cuando tenemos que aprender ese montón de algoritmos de ordenación, desde el Burbuja hasta el Quick Sort, búsquedas (secuenciales y binarias), inversiones, etc. La cuestión es que todo eso ya está hecho, no hay nada por inventar los grandes de la ciencia en computación demostraron cuáles son los mejores algoritmos y técnicas para realizar cada una de esas actividades; y es en ese punto en donde la programación orientada a objetos nos brinda justamente la posibilidad de utilizar objetos que implementan esos comportamientos. Por supuesto que si se realiza un producto de software que funcionará en un pequeño microprocesador (reproductora de video, microondas, lavarropas incluso un celular) que además cuenta con escasa memoria para ejecutar procesos, lo apropiado es implementar algoritmos simples que guarden relación con el volumen de información que procesan. El punto es: si vamos a ordenar 50 elementos del mismo tipo, es recomendable utilizar un algoritmo simple (alguna variante de burbuja); ahora si la cuestión es 50000 elementos del mismo tipo, bueno habrá que pensar en alguno de los más potentes. Justamente por esa razón los estudiantes de informática
Estructura de Datos y Arreglos en POO deben conocer las ventajas y desventajas de cada una de las técnicas de ordenación que hasta ahora se descubrieron.
Arreglos como objetos En los lenguajes no orientados a objetos los arreglos se implementan en una zona de memoria y su tamaño o dimensión se e4stablece cuando el desarrollador escribe el código; una vez generado el programa ejecutable no es posible cambiar la dimensión del arreglo. Esta situación nos presenta dos posibilidades, el arreglo es muy grande para la cantidad de elementos que se procesa o el arreglo se queda chico y no alcanza para ese volumen de elementos; cualquiera de estas posibilidades es lamentable dado que produce un producto software que no es robusto, o sea no es fuerte, no es resistente; dado que ante cualquier cambio en el volumen de información a procesar se desperdician los recursos o no alcanzan. Por otro lado, los elementos de los arreglos en los lenguajes no orientados a objetos deben ser todos del mismo tipo. Si el tamaño de estos elementos es variable es complicadísimo mantenerlos uno al lado del otro para poder acceder a cada uno de ellos por medio de uno o más índices. Los lenguajes orientados a objetos, implementan los arreglos como objetos y de acuerdo a lo explicamos en otra publicación sobre el stack y el heap que es el mecanismo cómo se administra la memoria para los objetos, se logran dos enormes ventajas. La primea es que todas las referencias son del mismo tamaño, de manera que no importa a qué tipo de objeto se esté referenciado, la referencia de un objeto tipo Persona ocupa la misma cantidad de memoria que una referencia a un objeto tipo Libro o lo que sea; de manera que es posible tener un arreglo de referencias y consecuentemente ya no es exigible que los elementos sean del mismo tipo; por supuesto que siempre lo serán dado que se trata de referencias, las que apuntan a objetos los que sí pueden ser de distinto tipo. La programación de este tipo de arreglos debe ser muy bien planificada y utilizará mecanismos polimórficos. La segunda ventaja que se obtiene en la POO relacionada con los arreglos es que al tratarse de objetos, es posible cambiar la cantidad de memoria que se reserva en el heap para un arreglo asignándole a la correspondiente referencia más o menos memoria con lo cual es posible en tiempo de ejecución modificar el tamaño o dimensión de un arreglo, resultando en un producto de software robusto, o sea que resiste a los cambios. El siguiente fragmento de código muestra esta posibilidad: double[] miVector = new double[50]; ... // esta parte del progrma carga datos en el vector double[] temp = new double[100]: for (int i = 0; i < 50; ++i) { temp[i] = miVector[i]; } miVector = temp;
Gracias al mecanismo de administración de memoria que los le nguajes orientados a objetos tienen es posible declarar un nuevo arreglo, copiar todos los valores que están en el actual arreglo y finalmente cambiar la referencia (miVector = temp). El recolector de basura libera la memoria que queda sin referenciar (la que estaba asignada inicialmente al arreglo) y el arreglo ahora tiene un nuevo tamaño.
Estructura de Datos y Arreglos en POO A continuación se muestran algunos de los métodos y propiedades que "entienden" los objetos del tipo Array en C# (MSDN para Visual Studio 2008).
Methods Name
Description
BinarySearch
Overloaded. Searches a one-dimensional sorted Array for a value, using a binary search algorithm.
Clear
Sets a range of elements in the Array to zero, to false, or to nullNothingnullptra null reference (Nothing in Visual Basic), depending on the element type.
Copy
Overloaded. Copies a range of elements in one Array to another Array and performs type casting and boxing as required.
Exists<(Of <(T>)>)
Determines whether the specified array contains elements that match the conditions defined by the specified predicate.
Find<(Of <(T>)>)
Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire Array.
FindAll<(Of <(T>)>)
Retrieves all the elements that match defined by the specified predicate.
FindIndex
Overloaded. Searches for an element that matches the conditions defined by a specified predicate, and returns the zero-based index of the first occurrence within an Array or a portion of it.
FindLast<(Of <(T>)>)
Searches for an element that matches the conditions defined by the specified predicate, and returns the last occurrence within the entire Array.
FindLastIndex
Overloaded. Searches for an element that matches the conditions defined by a specified predicate, and returns the zero-based index of the last occurrence within an Array or a portion of it.
GetLength
Gets a 32-bit integer that represents the number elements in the specified dimension of the Array.
of
GetLongLength
Gets a 64-bit integer that represents the number elements in the specified dimension of the Array.
of
GetValue
Overloaded. Gets the value of the specified element in
the
conditions
Estructura de Datos y Arreglos en POO the current Array. IndexOf
Overloaded. Returns the index of the first occurrence of a value in a one-dimensional Array or in a portion of the Array.
LastIndexOf
Overloaded. Returns the index of the last occurrence of a value in a one-dimensional Array or in a portion of the Array.
Resize<(Of <(T>)>)
Changes the size of an array to the specified new size.
Reverse
Overloaded. Reverses the order of the elements in a onedimensional Array or in a portion of the Array.
SetValue
Overloaded. Sets the specified element in the current Array to the specified value.
Sort
Overloaded. Sorts the elements in one-dimensional Array objects.
Properties Name
Description
IsReadOnly Gets a value indicating whether the Array is read-only.
Length
Gets a 32-bit integer that represents the total number of elements in all the dimensions of the Array.
Rank
Gets the rank (number of dimensions) of the Array.
Ejemplo de uso de un objeto del tipo Array 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
static void Main(string[] args) { int[] a1 = new int[5] { 5,4,3,2,1 }; Mostrar(a1); Console.WriteLine("Cambiamos el tamaño"); Array.Resize
(ref a1, 10); Mostrar(a1); Console.WriteLine("Lo ordenamos"); Array.Sort(a1);
Estructura de Datos y Arreglos en POO 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
Mostrar(a1); Console.WriteLine("Lo damos vuelta"); Array.Reverse(a1); Mostrar(a1); } /// /// Muestra el contenido de un arreglo de enteros /// /// Referencia al arreglo de enteros private static void Mostrar(int[] a) { Console.Write("Arreglo : "); foreach (int n in a) { Console.Write("{0,4}", n); } Console.WriteLine(); }
La salida es la siguiente:
Alternativa de comportamiento objetos del tipo ArrayList El problema que presentan los objetos del tipo Array es que todo el tratamiento se realiza para el total de los elementos del arreglo, y en la mayoría de las veces solamente se utiliza una parte del arreglo. Para solucionar esta cuestión, se cuenta con una declaración de clase que permite manipular una colección de elementos según se agreguen o saquen los elementos. El comportamiento implementado es funcionalmente mucho mejor que el que brinda un arreglo común y esto es porque se trata de la implementación de un tipo de dato abstracto conocido como Lista en Secuencia (tema de otra publicación). Si recordamos nuestros primeros algoritmos con arreglos (en lenguajes no orientados a objetos) vamos ver que siempre hacía falta indicar cuantos elementos de un arreglo se estaban utilizando. funcion SumaVector(TipoVector V, Entero N) : Real
En este encabezado de función se indica que se trata de una función que por su nombre debe sumar el contenido de los elementos del parámetro "V" que es del tipo "TipoVector" y se indica con el parámetro "N" que es un entero la cantidad de elementos válidos dentro del vector.
Estructura de Datos y Arreglos en POO Este modelo de programación es laborioso dado que el desarrollador debe mantener con mucho cuidado la relación que existe entre el vector "V" y el valor "N" que indica cuantos elementos hay en dicho vector. Por supuesto que esto se podría hacer mejor implementando un registro: Registro VectorVariable TipoVector V Entero N Fin-Registro ... VectorVariable datos;
Donde la variable denominada "datos" es en realidad un registro que mantiene en la misma estructura el vector y el número de elementos válidos. A cada "campo" del registro se accede con el selector de campos, por ejemplo: datos.V[0] = 56 datos.V[1] = 34 datos.N = 2
Por supuesto que el desarrollador tiene la obligación de controlar que el valor del campo "N" no supere el tamaño o dimensión del arreglo "V", además no puede ser negativo y tendrá que codificar todos los algoritmos que hagan falta para manipular la información almacenada en los elementos que el vector contiene. Contar con una definición de objetos que nos brinda la posibilidad de automáticamente controlar la cantidad de elementos válidos dentro del arreglo y además redimensionar el arreglo cuando sea necesario es una herramienta fabulosa, que además incorpora comportamiento para ordenar los elementos, insertar elementos nuevos o duplicados, remover el que se desee, buscar, etc. A continuación se muestran algunos de los métodos y propiedades que "entienden" los objetos del tipo ArrayList en C# (MSDN para Visual Studio 2008).
Constructors Name
Description
ArrayList Overloaded. Initializes a new instance of the ArrayList class.
Methods Name
Description
Add
Adds an object to the end of the ArrayList.
AddRange
Adds the elements of an ICollection to the end of the ArrayList.
Clear
Removes all elements from the ArrayList.
Contains
Determines whether an element is in the ArrayList.
Estructura de Datos y Arreglos en POO
CopyTo
Overloaded. Copies the ArrayList or a portion of it to a one-dimensional array.
IndexOf
Overloaded. Returns the zero-based index of the first occurrence of a value in the ArrayList or in a portion of it.
Insert
Inserts index.
an
element
into
the
ArrayList at
the
specified
InsertRange Inserts the elements of a collection into the ArrayList at the specified index. LastIndexOf Overloaded. Returns the zero-based index of the last occurrence of a value in the ArrayList or in a portion of it. Remove
Removes the first occurrence of a specific object from the ArrayList.
RemoveAt
Removes the element at the specified index of the ArrayList.
Reverse
Overloaded. Reverses the order ArrayList or a portion of it.
Sort
Overloaded. Sorts the elements in the ArrayList or a portion of it.
ToArray
Overloaded. Copies the elements of the ArrayList to a new array.
TrimToSize
Sets the capacity to the actual number of elements in the ArrayList.
of
the
elements
in
the
Properties Name
Description
Capacity Gets or sets the number of elements that the ArrayList can contain. Count
Gets the number ArrayList.
of
elements
actually
contained
in
the
Estructura de Datos y Arreglos en POO
Item
Gets or sets the element at the specified index.
Ejemplo de uso de un objeto del tipo ArrayList 1: using System; 2: using System.Collections; 3: 4: namespace ArrayList1 5: { 6: class Program 7: { 8: static void Main(string[] args) 9: { 10: ArrayList al1 = new ArrayList(); 11: al1.Add(18); 12: Mostrar(al1); 13: al1.Add(1); 14: Mostrar(al1); 15: al1.Add(45); 16: Mostrar(al1); 17: al1.Add(18); 18: Mostrar(al1); 19: 20: Console.WriteLine("Insertamos 516 en la posición 3\n(recordar que todo comienza en cero)"); 21: al1.Insert(2, 516); 22: Mostrar(al1); 23: 24: Console.WriteLine("Sacamos un elemento cuyo valor es 45"); 25: al1.Remove(45); 26: Mostrar(al1); 27: } 28: 29: /// 30: /// Muestra el contenido de un objeto ArrayList 31: /// 32: /// Referencia al objeto ArrayList 33: private static void Mostrar(ArrayList al1) 34: { 35: Console.WriteLine("ArrayList : "); 36: foreach (object o in al1) 37: { 38: Console.WriteLine("{0,4}", o.ToString()); 39: } 40: Console.WriteLine(); 41: } 42: 43: } 44: }
La salida es la siguiente:
Estructura de Datos y Arreglos en POO
Recomendación Sabiendo que se pueden utilizar estos tipos de objetos, el desarrollo de productos de software utilizando lenguajes orientados a objetos de ninguna manera admite que se invente la rueda a cada rato, es imprescindible utilizar estas herramientas.