Estructuras Lineales

Para poder hablar en forma ordenada de estructuras de datos es necesario establecer una taxonomía de ellas en base en uno o varios criterios de clasificación. En general se pueden considerar dos, uno que toma en cuenta la estructura interna desde el punto de vista conceptual, y otro que se basa en la forma de almacenar los elementos que conforman la estructura de datos o nodos.

El primer criterio divide las estructuras de datos en estructuras lineales y estructuras no lineales, según la relación entre los elementos que las conforman se realice a lo largo de una sola dimensión o que no sea así.

De acuerdo al segundo criterio, las estructuras de datos se dividen en secuenciales y no secuenciales o con apuntadores, según que los nodos se encuentren físicamente contiguos o no en la memoria de la computadora.

Las operaciones que se pueden definir sobre una estructura lineal son las siguientes:

1.- Hacer referencias al elemento k, examinarlo y/o modificarlo en alguna forma.

2.- Insertar un nuevo elemento justo antes (o después) del elemento k.

3.- borrar el elemento k.

4.- Dividir una estructura en dos.

5.- Combinar dos estructuras en una.

6.- Copiar una estructura.

7.- ordenar los elementos de una estructura de acuerdo a algún criterio.

8.- Buscar uno o todos los elementos que cumplan algún criterio.

Arreglos Unidimensionales

Entre las estructuras secuénciales, las más sencillas y conocidas son, sin lugar a duda, los arreglos unidimensionales. Como estructura abstracta de datos, podemos definir un arreglo unidimensional de algún tipo de datos objeto, de acuerdo a las siguientes funciones:

CREA: 0 ? {ARREGLOS}
GUARDA: {ARREGLOS} x {INDICES} x {OBJETOS} ? {ARREGLOS}
EXTRAE: {ARREGLOS} x {INDICES} ? {OBJETOS}

En general, los índices suelen ser números enteros consecutivos, y rara vez indica como error el consultar un arreglo no inicializado, lo cual es fuente de frecuentes errores en programación. En algunos sistemas, los arreglos se inicializan con un valor especial, generalmente cero; en este caso, habría que modificar la última restricción.

Desde el punto de vista de la implantación, se puede caracterizar los arreglos unidimensionales en la siguiente forma:

1.- Estructura fija, definida por un limite inferior L, un límite superior S y un numero de palabras ñ por nodo.

2.- Acceso aleatorio a cualquier nodo del arreglo con base en un índice I

Si bien muchos lenguajes de alto nivel establecen restricciones arbitrarias sobre alguna de estas características, por ejemplo límite inferior necesariamente igual a 0 o 1, o una palabra (o máximo dos) por nodo, como se verá más adelante, éstas son restricciones artificiales.

Para determinar la localización de un elemento en particular, es necesario obtener primero un índice efectivo E que compense el hecho de que el límite inferior no sea cero y multiplicarlo por el numero de palabras (o caracteres) por nodo de información, para obtener finalmente un desplazamiento D, que defina la distancia entre el elemento inicial del arreglo y el que se busca.

Arreglos (array)

Un arreglo (array) es una secuencia de elementos. Todos los elementos de un arreglo tienen el mismo tipo. Los elementos de un arreglo viven en un bloque de memoria contiguo y se accede a ellos por medio de índices enteros, al contrario de los datos de una clase que se acceden a ellos por medio del nombre.

Para declarar un arreglo se usa el patrón estándar de . Se declara un tipo arreglo a la izquierda escribiendo el nombre del tipo de elemento seguido por un par de corchetes. Los corchetes significan que la variable es un arreglo (array).Por ejemplo:

int [ ] numeros;

Para crear una instancia de array, se utiliza la palabra clave new seguida por el nombre del tipo de arreglo y entre los corchetes se indica el tamaño. Por ejemplo:

new int [ 4 ];

Una forma para optimizar el diseño de nuestra clase, es colocar en una sola instrucción la declaración y la creación de una instancia de tipo array. Por ejemplo:

int [ ] numeros = new int [ 4 ];

De la misma manera se puede emplear que el usuario introduzca el tamaño del array. El conjunto de instrucciones sería de la siguiente manera:

int tamaño=  int.Parse(Console.Readline());
int [ ] numeros = new int [ size ];

Arreglos bidimensionales

La declaración es de la siguiente manera:

int [ , ] matriz = new int [ 4,6 ];

Al crearse una instancia array, todos los elementos de la instancia se inicializan a un valor predeterminado, que depende de su tipo. Por ejemplo; de tipo entero se inicializa en cero, de tipo booleano se inicializa en false. Para asignarle valores a los elementos del array creado se colocan los valores dentro de llaves {} separados entre comas, como por ejemplo:

int [ , ] numeros = new int [ 4] { 9,3,7,2};

Nota: El número de los valores que hay entre las llaves tiene que coincidir exactamente con el tamaño de la instancia del array que se está creando.

Ejemplo:

using System;

//Definición del Espacio de Nombres para la Clase "Matriz"
namespace MatrizClass
{
//Inicio de las Definiciones para la Clase "Matriz"
class Matriz
 {
   //Arreglo de Enteros para el Objeto "Matriz"
   int[,] Arreglo = new int [11,11];

   /*Variables que Indican el Tamaño del Arreglo del Objeto 
   "Matriz"*/
   int ren;
   int col;

   //Constructor por Defecto
   Matriz()
   {
      ren = 10;
	col = 10;
	//Ciclo para Incrementar los Renglones
	for( int R=0; R<=10; R++)
	{
	   //Ciclo para Incrementar las Columnas
	   for( int C=0; C<=10; C++)
	   {
		/*Asignacion de Valores "cero" en las 
		Localidades del Arreglo*/
		Arreglo[R,C]=0;
	   }
	}
   }
   //Fin del Constructor por Defecto

   //Constructor Sobrecargado
   Matriz( int CantR, int CantC )
   {
   	Console.WriteLine("\nLlenado de La Matriz ... \n");

	/*Revision de que los Parametros "CantR" y "CantC" son 
	Menor a "dos" (Para que la matriz sea Valida)*/
	if( CantR<2 || CantC<2 )
	{
	   //Peticion y Lectura del Tamaño de la Matriz
	   Console.Write("Introduce la Cantidad de Renglones:");
	   CantR = int.Parse( Console.ReadLine() );
			
	   Console.Write("Introduce la Cantidad de Columnas:");
	   CantC = int.Parse( Console.ReadLine() );
	   Console.WriteLine("\n");
	}

	//Ciclo para Incrementar los Renglones
	for( int R=0; R<=(CantR-1); R++)
	{
	   //Ciclo para Incrementar las Columnas
	   for( int C=0; C<=(CantC-1); C++)
	   {
	 	/*Peticion y Lectura de Valores para las 
		Localidades del Arreglo*/
		Console.Write("Introduce el Valor de la 
		  Localidad ["+(R+1)+"],["+(C+1)+"] : ");
		Arreglo[R,C] = int.Parse(Console.ReadLine());
	   }

	}
	ren = CantR-1;
	col = CantC-1;
   }
   //Fin del Constructor Sobrecargado

   Matriz SumaMatrices ( Matriz Recibida )
   {
	//Creacion de la Matriz "Resultado"
	Matriz Resultado = new Matriz ();

	//Revision de las Dimensiones de las Matrices a Sumar.
	if(ren == Recibida.ren || col == Recibida.col)
	{
	   //Dimencionamiento de la Matriz "Resultado" 
	   Resultado.ren = ren;
	   Resultado.col = col;

	   //Ciclo para Incrementar los Renglones
	   for( int R=0; R<=ren; R++)
	   {
		//Ciclo para Incrementar las Columnas
		for( int C=0; C<=col; C++)
		{
		   //Realizacion de Operaciones
		   Resultado.Arreglo[R,C] = 
		     Recibida.Arreglo[R,C] + Arreglo[R,C];
		}
	   }
	}
	return Resultado;
   }

   void ImprimeMatriz ()
   {
	Console.WriteLine("\n");
	//Ciclo para Incrementar los Renglones
	for( int R=0; R<=ren; R++)
	{
	   //Ciclo para Incrementar las Columnas
	   for( int C=0; C<=col; C++)
	   {
		/*Impresion de los Valores en las Localidades
		del Arreglo*/
		Console.Write(Arreglo[R,C]+"\t");
	   }
	   /*Impresion de un Salto de Carro al Termino de Cada 
	   Renglon*/
	   Console.Write("\n");
	}
	Console.WriteLine("\n");
   }

   [STAThread]
   static void Main( )
   {
	Matriz A = new Matriz(0,0);
	Matriz B = new Matriz(0,0);
	Matriz C = new Matriz();
			
	Console.WriteLine("\nLa Suma de las Matrices Es:");
	C = A.SumaMatrices( B );
	C.ImprimeMatriz();
   }
 }
}

Para la lectura y escritura en los elementos de un array se utiliza el siguiente conjunto de instrucciones:

int [ ] pins = {3,2,7,9};
for( int index=0; index !=pins.Length; index++)
{
	int pin = pins[index];
	Console.WriteLine(pin);
}

Uso de la Clase ArrayList

ArrayList es una clase útil para reordenar los elementos en un array. Entre las ventajas que tiene el usar esta clase, están los siguientes casos:

   Se puede quitar un elemento de un ArrayList usando su método Remove.

   Se puede añadir un elemento al final de un ArrayList usando el método Add.

   Se puede insertar un elemento en medio de un ArrayList usando el método Insert.