Você está na página 1de 38

DISEO DE ESTRUCTURAS DE

DATOS Y ALGORITMOS

NDICE

1.

Unidad didctica 1 Estructuras estticas y dinmicas ......................................4


1.1. Variables.............................................................................................................. 4
1.2. Declaracin.......................................................................................................... 4
1.3. Tipos de datos..................................................................................................... 4
1.4. Identificadores ..................................................................................................... 4
1.5. Variables locales.................................................................................................. 5
1.6. Variables globales................................................................................................ 5
1.7. Constantes............................................................................................................ 6
1.8. Palabras clave ...................................................................................................... 7
1.9. Operadores aritmticos ........................................................................................ 7
1.10. Operadores relacionales....................................................................................... 8
1.11. Operadores lgicos .............................................................................................. 8
1.12. Operadores de asignacin.................................................................................... 8
1.13. Sentencias simples............................................................................................... 8
1.14. Sentencias compuestas ........................................................................................ 8
1.15. Sentencias alternativas o condicionales............................................................... 9
1.15.1. Sentencia alternativa simple/doble ifelse ................................................. 9
1.15.2. Operador (?).................................................................................................. 9
1.15.3. Sentencia alternativa mltiple switch ......................................................... 10
1.16. Sentencias de iteracin ...................................................................................... 11
1.16.1. Sentencia while........................................................................................... 11
1.16.2. Sentencia do-while ..................................................................................... 12
1.16.3 Sentencia for ................................................................................................ 12
1.17 Arrays ................................................................................................................. 13
1.17.1 Declaracin de Arrays Unidimensionales ................................................. 14
1.17.2 Uso de Arrays Unidimensionales .............................................................. 15
1.17.3 Funciones ms comunes con arrays ........................................................... 16
1.17.4 Foreach para el manejo de arrays .............................................................. 16
1.17.5 Ejemplos de declaracin y uso de arrays ................................................... 17
1.18 Arrays Multidimensionales ................................................................................ 18
1.18.1 Declaracin de Matrices ............................................................................. 19
1.18.2 Uso de Matrices......................................................................................... 20
1.18.3 Obteniendo Dimensiones de una Matriz .................................................... 20
1.18.4 Ejemplos de uso de Matrices ...................................................................... 20
1.18.5 Foreach en matrices .................................................................................... 20
1.19 Enumeraciones.................................................................................................... 21
2. Unidad didctica 2 Estructuras estticas y dinmicas ....................................23
2.1 Introduccin......................................................................................................... 23
2.2 Algoritmos de Bsqueda Simple......................................................................... 23
2.2.1 Bsqueda Lineal ......................................................................................... 23
2.3 Algoritmos de Ordenamiento .............................................................................. 26
2.3.1 Ordenamiento por Seleccin ...................................................................... 26
2.3.2 Ordenamiento por Seleccin (versin iterativa)......................................... 28
2.4 Complejidad de Algoritmos ................................................................................ 31
2.4.1 Ordenamiento y Bsqueda Eficientes ........................................................ 31
2.5 Algoritmos Eficientes de Bsqueda .................................................................... 33
2.5.1 Bsqueda Binaria........................................................................................ 33
2.5.2 Algoritmo de Ordenamiento: Quicksort..................................................... 35
2.6 Pilas y colas (Stack & Queue)............................................................................. 36

1. Unidad didctica 1 Estructuras estticas y dinmicas

1.1. Variables
Una variable es una posicin de memoria con nombre (identificador) que se usa para
mantener valores que pueden ser modificados durante el programa.

1.2. Declaracin
Las variables deben estar previamente declaradas antes de poder hacer referencia a
las mismas.
La declaracin de las variables ser de la forma:
tipo nombre_variable;

Donde tipo ser un tipo de datos vlido y nombre_variable ser el identificador de


la misma.
La posicin dnde se declaran las variables vendrn dadas por las necesidades de
mbito de las mismas; siendo locales, las que se declaran dentro de funciones o
mtodos y globales, las que se declaran fuera de toda funcin o mtodo.
La asignacin de valores a las variables podr realizarse de las siguientes formas:
Forma 1:
int edad;
edad = 12;

Forma 2:
int edad = 12;

1.3. Tipos de datos


Los tipos de datos primitivos de variables pueden ser:
int, long, float, double, decimal, string, char

y bool.

1.4. Identificadores
Son nombre_variable que se utilizan para representar variables, constantes, tipos y
funciones de un programa.
Se construyen con secuencias de una o ms letras, dgitos o smbolos de subrayado.
Los identificadores segn el estndar ANSI deben:

- Comenzar por una letra o smbolo de subrayado.

- No deben exceder de 32 caracteres.


- Los compiladores suelen ser sensibles a maysculas y minsculas.
- Los identificadores no deben tener la misma secuencia de caracteres que
una palabra clave o una funcin predefinida.
- Los identificadores deben ser significativos para la aplicacin que se est
programando.

1.5. Variables locales


Las variables que se declaran dentro de un bloque (entendemos por bloque una
sentencia compuesta delimitada por {}), se denominan variables locales.
Estas variables slo son conocidas dentro del bloque donde han sido declaradas, por
lo que slo las pueden referenciar sentencias de su mismo bloque.
Las variables locales slo existen durante la ejecucin del bloque de cdigo en el que
son declaradas, despus se destruyen, por lo que se pierde el contenido de las
mismas; no retienen valores.
En el siguiente ejemplo, la variable dato de la funcion_1 no tiene nada que ver con la
variable dato de la funcion_2
static void funcion_1()
{
int dato;
dato = 2;
}
static void function_2()
{
int dato;
dato = 111;
}
Tambin se pueden declarar variables locales en cualquier bloque de cdigo del
programa. Por ejemplo dentro de un bloque if else, for, foreach, etc.

1.6. Variables globales


Se declaran fuera de cualquier bloque, normalmente, al principio del programa.
Las variables globales son conocidas en todo los bloques del programa y se pueden
acceder desde cualquier bloque del mismo.

Ocupan memoria durante toda la ejecucin del programa.

Si en un bloque se declara una variable local con el mismo nombre que una variable
global, cuando se use el identificador dentro del bloque se har referencia a la
variable local.
Sern variables distintas almacenadas en distintas posiciones de memoria.
Slo se deben declarar las variables globales necesarias, ya que en programas
grandes puede provocar efectos laterales como modificaciones no deseadas.
En el siguiente ejemplo, en la funcion_1la variable temporaltendr el valor de la
variable global edad(12) mientras que en la funcion_2la variable temporal, tendr el
valor de la variable local edad(200)
static int edad;
static void Main(string[] args)
{
edad = 12;
funcion_1();
}
static void funcion_1()
{
int temporal = edad;
function_2();
}
static void function_2()
{
int edad = 200;
int temporal = edad;
}

1.7. Constantes
Una constante es una variable cuyo valor no puede alterarse por el programa; como
variables, tendr un identificador o nombre que se asocia al valor de la constante.
Se pueden definir constantes de cualquiera de los tipos de datos.
Una constante no podr aparecer a la izquierda del signo de asignacin igual (=),
salvo en su inicializacin.
Para declarar e inicializar constantes se har con la palabra CONST seguido del tipo
de dato y el nombre identificativos de la variable, preferiblemente con todas las
letras en maysculas.
Por ejemplo:
const double PI = 3.14;

1.8. Palabras clave


Son identificadores predefinidos que tienen un significado especial para el
compilador. Slo se pueden usar de la forma que se han definido.
Por ejemplo:
const
string
null
enum
try
do
protected

readonly
struct
base
class
catch
while
internal

new
int
parcial
override
finally
foreach
static

void
interface
abstract
virtual
throw
public
goto

this
delegate
sealed
using
for
private

1.9. Operadores aritmticos


Los operadores aritmticos son:
Operador
+
*
/
%
-++

Accin
Resta
Suma
Multiplicacin
Divisin
Resto de divisin
Decremento
Incremento

Cuando el operador de divisin (/) se aplica a dos operandos de tipo int, el resto se
desprecia (los decimales no se guardan) y se denomina divisin entera. En caso
contrario es una divisin real.
El operador del resto de la divisin (%) no se puede aplicar a los tipos de coma
flotante
(slo para divisiones enteras).
Los operadores de incremento y decremento (++ y --) se pueden usar antes de las
variables o despus, con significados diferentes:
++variable variable++
--variable variable-Si el operador (++ --) precede a la variable (se pone antes), se realiza primero el
incremento o el decremento y despus usa el valor de la variable.
Si el operador (++ --) sigue a la variable (se pone despus), se usa primero el valor
de la variable y despus realiza el incremento o el decremento.

1.10. Operadores relacionales


Operador
>
<
>=
<=
==
!=

Accin
Mayor que
Menor que
Mayor o igual que
Menor o igual que
Igual a
Distinto de

1.11. Operadores lgicos


Operador
&&
||
!

Accin
AND
OR
NOT

1.12. Operadores de asignacin


Por lo general, el operador de asignacin es el signo igual (=) y se usa de la siguiente
forma:
<variable> = <expresin>;

1.13. Sentencias simples


Una sentencia simple es una expresin vlida en C# acabada en punto y coma (;)
Por ejemplo:
int dato;
dato = 2;

1.14. Sentencias compuestas


Las sentencias compuestas son grupos de sentencias que se tratan como si fueran un
nica sentencia.
Las sentencias compuestas comienzan con una llave de apertura { y se terminan con
la llave de cierre o complementaria }.
Generalmente las sentencias compuestas se usan para indicar el conjunto de
operaciones a realizar cuando se cumplen ciertas condiciones (estructuras if-else), o
bien el conjunto de operaciones que se quieren repetir hasta que se cumpla una
condicin (estructuras for, while,)

1.15. Sentencias alternativas o condicionales


Se utilizan en puntos del programa donde sea necesario comprobar una condicin.
Se ejecutarn unas sentencias u otras dependiendo de si la condicin es cierta o
falsa.
1.15.1. Sentencia alternativa simple/doble ifelse
La sentencia alternativa simple if tiene la siguiente forma:
if (expresin)
{
sentencias-1;
...
}
sentencias-n;
Si la expresin es cierta (true) se ejecutan las sentencias-1; si es falsa (false), no se
ejecutan. En ambos casos, el programa continuar por el punto sentencias-n.
La sentencia alternativa doble if...elsetiene la siguiente forma:
if (expresin)
{
sentencias-1;
...
}
else
{
sentencias-2;
...
}
sentencias-n;
Si la expresin es cierta (true) se ejecutan las sentencias-1; si es falsa (false), se
ejecutan las sentencias-2. En ambos casos, el programa continuar por el punto
sentencias-n.
Nunca se ejecutarn ambos grupos de sentencias: sentencias-1 y sentencias-2.

1.15.2. Operador (?)


El operador ? es equivalente a una sentencia if...else. Las siguientes estructuras son
equivalentes:
// primera forma..
variable = expresin-1 ? expresin-2 : expresin-3;

// segunda forma..
if (expresin-1)
variable = expresin-2;
else
variable = expresin-3;

1.15.3. Sentencia alternativa mltiple switch


Se compone de las palabras clave switch, case, defaulty break. La sentencia switch
tiene la siguiente forma:
switch (expresin)
{
case constante-1:
sentencias-1;
...;
break;
case constante-2:
sentencias-2;
...;
break;
default:
sentencias-n;
...;
break;
}
Se compara la expresin con cada una de las constantes-i; cuando coincide la
expresin con la constante, se ejecutarn las sentencias-i asociadas a esa constante.
La sentencia break no es obligatoria, pero si no se pone, el programa despus de
ejecutar sentencias-i continuar con los siguientes case, comprobando la expresin
con las siguientes constantes.
Las constantes pueden ser enteras o de caracteres.
La sentencia default es opcional; sus sentencias-n asociadas se ejecutarn cuando la
expresin no ha coincidido con ninguna de las constantes-i.
switch slo puede comprobar la igualdad y adems slo trabaja con variables
enteras o de caracteres.
Dentro de un case no se pueden poner llaves. Ejemplo:
static void Main(string[] args)
{
Console.Write("Introduzca un nmero: ");

10

int num = int.Parse(Console.ReadLine());


switch (num)
{
case 1: case 2: case 3:
Console.Write("el nmero es un 1 un 2 un 3)");
break;
case 4:
case 5:
Console.Write("el nmero es un 4 un 5");
break;
default:
Console.Write("nmero no encontrado");
break;
}
Console.Read();
}

1.16. Sentencias de iteracin


Son las sentencias que nos permiten repetir un conjunto de sentencias mientras se
cumpla una determinada condicin.
1.16.1. Sentencia while
La sentencia while tiene la siguiente forma:
while (condicin)
{
sentencias;
...;
}
sentencias-siguientes;
Si la condicin es cierta se ejecutan las sentencias; al llegar a la llave de cierre } se
vuelve a evaluar la condicin; si vuelve a ser cierta, se ejecutan de nuevo las
sentencias. Y as sucesivamente. Cuando en algn momento la condicin sea falsa
(false), el programa continuar por el punto de sentencias-siguientes, ya fuera del
while.
Hay que asegurarse que la condicin est inicializada, es decir, que todas las
variables que intervengan en la misma tengan algn valor. Adems, tambin hay
que asegurarse de que en algn momento no se cumpla la condicin para que el
programa salga del bucle.
Ejemplo:
string resp = "S";

11

while (resp == "S")


{
Console.Write("Desea continuar [S/N]? ");
resp = Console.ReadLine();
}

1.16.2. Sentencia do-while


La sentencia do-while tiene la siguiente forma:
do
{
sentencias;
...;
}
while (condicin);
sentencias-siguientes;
En la sentencia do-while primero se ejecutan las sentencias; despus, se comprueba
la condicin; si es cierta (true), se vuelve a ejecutar las sentencias y se vuelve a
evaluar la condicin. Y as sucesivamente. Cuando en algn momento la condicin
sea falsa (false), el programa continuar por el punto sentencias-siguientes ya fuera
de la estructura do- while.
Con do-while, al contrario que con while, se ejecutan las sentencias y despus se
evala la condicin, por lo que las sentencias se ejecutarn al menos una vez.
Ejemplo:
string resp;
do
{
Console.Write("Desea continuar [S/N]? ");
resp = Console.ReadLine();
}
while (resp == "S");

1.16.3 Sentencia for


La sentencia for tiene la siguiente forma:
for(expresin-1; expresin-2; expresin-3)
{
sentencias;
...;
}

12

El uso habitual es:


- expresin-1: se usa para inicializar las variables de control del bucle, es decir las
que intervienen en la condicin del bucle.
- expresin-2: se usa para la condicin de permanencia del bucle; si esta expresin
es cierta se repite de nuevo el bucle.
- expresin-3: se usa para modificar las variables de control del bucle, para que no
sea un bucle infinito.
Por lo que la sentencia for se podra escribir de la siguiente forma:
for(inicializacin; condicin; progresin)
{
sentencias;
...;
}
Siendo el orden de ejecucin el siguiente:
1.
2.
3.
4.

Se ejecuta la inicializacin.
Se comprueba la condicin.
Si es cierta, se ejecutan las sentencias.
Se ejecuta la progresin y se vuelve al paso 2.

Y as sucesivamente hasta que la condicin sea falsa (false). Ejemplo:


for (int i = 1; i <= 10; i++)
{
Console.WriteLine(i);
}
Console.Read();
Si queremos que un bucle finalice en algn momento antes que la condicin del
mismo deje de cumplirse, usaremos la sentencia break. Esta sentencia hace que la
siguiente instruccin salte fuera del bucle.

1.17 Arrays
Los arrays son estructuras de datos complejas (en el sentido de que no son atmicas)
que agrupan datos de un mismo tipo en particular, llamado el tipo base del array. El
tipo base de un array puede ser cualquiera de los tipos bsicos de C#, o incluso algunos
tipos complejos como las clases.
Un array es tambin ejemplo de un modelo. Un array puede considerarse como ejemplo
de una variable compuesta capaz de almacenar uno o ms datos al mismo tiempo.
La sintaxis del lenguaje permite referirse a cada uno de los elementos que constituyen

13

el array empleando ndices. Esto es posible pues los elementos del array estn
numerados en forma jerrquica y consecutiva, empezando en 0 en cada dimensin.
El siguiente grfico ilustra un ejemplo de un array llamado numeros, cuya posicin 0
almacena el valor 10, la posicin 1 el valor de 21, etc. Este array en total almacena n+1
elementos. El valor de n, depende de la memoria que pueda tener el computador y el
tipo de elementos que se almacenen en el array.

Los arrays, al igual que el resto de las variables se identifican con un nombre. Al
emplear ese nombre, se hace referencia a la estructura de datos como un todo, es decir,
con todos sus elementos. El lenguaje interpreta dicho nombre como un puntero.
Cuando se utiliza el nombre del array en forma indexada, es decir, combinado con
ndices, se hace referencia a un elemento particular, del tipo base, dentro de la
estructura compleja.
Importante: El lenguaje C# no controla la validez de los ndices que se emplean para
referenciar un array. Esto quiere decir que es posible cometer errores graves y
difciles de detectar en este sentido. Ms adelante se presenta un ejemplo en este
sentido.
1.17.1 Declaracin de Arrays Unidimensionales
Los arrays, al igual que las dems variables deben declararse antes de poder utilizarlas,
y cumplen con las mismas reglas de alcance y vida.
Los arrays de una sola dimensin reciben tambin el nombre de vectores. La sintaxis
de la declaracin de un array unidimensional es la siguiente:
<tipo-base>[] <identificador>;
Observaciones:
El <tipo-base>puede ser cualquiera de los tipos bsicos del lenguaje, o incluso
algunos complejos como estructuras.

El <identificador> es el nombre que distinguir el array.

Los corchetes [ ] son obligatorios y denotan que el identificador descrito, del


tipo-base indicado, es un array (lista de elementos del tipo base).
En esta declaracin NO se define el tamao que tendr el array (aunque se puede
determinar las dimensiones, lo que se ver ms adelante).
El tamao del array se determina en una segunda declaracin, que puede ir en la
siguiente lnea, como se muestra a continuacin.
<identificador> = new <tipo-base> [<NumElementos>]
En esta declaracin, se dimensiona el array con una cantidad determinada de
elementos, todos correspondientes a tipo-base.
Es posible hacer la declaracin del array y su dimensionamiento en una
misma sentencia:

14

<tipo-base>[ ] <identificador> = new <tipo-base>[<NumElementos>]


Adicionalmente es factible declarar, dimensionar, e inicializar un array con todos sus
elementos, en una sola declaracin:
<tipo-base>[ ] <identificador> = {valor1, valor2, ..., valorN};
Esta ltima declaracin implcitamente dimensiona el array para almacenar los N
elementos descritos, por lo que no se requiere dimensionarlo aparte.
Es decir:

Con los valores indicados entre llaves {} se inicializarn los elementos del array.
Los valores deben ser del <tipo-base> del array
Tambin es factible declarar, dimensionar, e inicializar un array con todos sus
elementos, en una sola declaracin, pero slo indicando un subconjunto de los
valores que el array puede guardar:

<tipo-base>[] <identificador> = new <tipo-base>[N] {valor1, ..., valorM};


... donde M<N, y N debe ser una expresin constante, como por ejemplo 10. Es factible
hacer una declaracin donde M>N, en cuyo caso, el real dimensionamiento del array se
regir por M.
Algunos ejemplos:
// Array para 10 enteros int [] numeros;
numeros = new int[10];
// Array para 10 enteros
int [] numeros = new int[10];
// Array para 10 enteros
int [] numeros = { 1, 1, 1, 2, 3, 5, 2, 5, 3, 4 };

1.17.2 Uso de Arrays Unidimensionales


Los elementos de un array son variables del tipo base del vector, por lo que se utilizan
de la misma manera en expresiones y dems instrucciones, como la asignacin. Por
ejemplo, para asignar un valor a un elemento de un array basta con escribir:
<array>[indice] = <expresion>;
donde <array> es el nombre de la variable e indice hace referencia a la posicin del
elemento al que se le quiere asignar el <expresion>. La referencia de valores en un
array, se indexa desde el 0 al N-1.
Importante: Puesto que los arrays son estructuras complejas (es decir, no bsicas), no
es posible asignar un array a otro mediante una simple asignacin (=). Para hacer
esto es necesario escribir un ciclo y asignar elemento a elemento.
Como se mencion anteriormente, el lenguaje C# no controla la validez de los
ndices que se emplean para referenciar un array. Esto quiere decir que es posible
cometer errores muy difciles de detectar en este sentido. Es necesario prestar especial
inters a los valores que toman los ndices para evitar estos problemas.

15

Por ejemplo, la siguiente porcin de cdigo compila sin problemas (es decir, sin
errores sintcticos), pero probablemente produzca un error en tiempo de ejecucin
al referenciarse posiciones inexistentes del array.
// Las posiciones con ndices del 10 al 19 son invlidas.
int[] array = { 1,1,1,1,1,1,1,1,1,1 }; // 10 elementos int i;
for (i=0; i<20; i++)
array[i] = 0; // Error para i >= 10
Tambin es comn cometer estos errores olvidando que las posiciones de los arrays
estn numeradas a partir del ndice cero. Es decir, en un array de tamao N
las posiciones estn numeradas de 0 a N-1.

1.17.3 Funciones ms comunes con arrays


En C#, los arrays se representan con un tipo especfico, y por ello cuentan con sus
propios atributos y mtodos especficos. Por ejemplo, para obtener el largo (la cantidad
de elementos dimensionados) de un array, o para ordenarlo.
El Largo de un Array
En el caso de los arrays unidimensionales, el tamao o cantidad de elementos se obtiene
con la propiedad Length.
int [] numeros = { 1,2,3,4,5,6 };
Console.WriteLine(Largo: {0}, numeros.Length);
Ordenamiento de un Array
En el caso de los arrays que sean de uno de los tipos predefinidos (int, float, char,
etc.), es factible ordenarlos en forma creciente, aprovechando el mtodo bsico Sort()
de la clase Array:
int [] numeros = { 4,5,2,3,1,6 };
Array.Sort(numeros); // 1,2,3,4,5,6
Revertir el Orden de un Array
En el mismo caso en que se pueda ordenar un array, se puede reordenar
exactamente al revs de cmo est, aprovechando el mtodo bsico Reverse() de la
clase Array:
int [] numeros = { 1,2,3,4,5,6 };
Array.Reverse(numeros); // 6,5,4,3,2,1

1.17.4 Foreach para el manejo de arrays


Existe esta sentencia de control de flujo, especialmente diseada para este tipo de
estructuras, donde se manejan listas de elementos, todos del mismo tipo. Foreach

16

depende de la definicin previa de un array de elementos del mismo tipo, los cuales
puede recorrer individualmente sin conocer el tamao explcitamente (como se requiere
en otras instrucciones, por ejemplo en el for).
La sintaxis de uso es:
foreach ( <tipo> <variable> in <array> )
{
<instrucciones>
}
Donde:

<tipo> es el tipo bsico de los elementos contenidos en el array.

<array> es el array de elementos a revisar.

<variable> es un identificador de una variable local del foreach() que se


usar para ver un elemento del array en cada iteracin.
Ejemplo:
using System;
class MainClass
{
public static void Main()
{
int impares = 0, pares = 0;
int[] arr = new int [] {0,1,2,5,7,8,11};
foreach (int i in arr)
{
if (i%2 == 0)
pares++;
else impares++;
}
Console.WriteLine("Hay {0} impares y {1} pares.", impares, pares);
Console.ReadLine();
}
}
1.17.5 Ejemplos de declaracin y uso de arrays
En todos los casos, A es el nombre de la variable declarada:
1. Declaracin de un array de 50 enteros:
int[] A = new int[50];
2. Declaracin de un array de 100 caracteres:
char[] A = new char[100];
3. Declaracin e inicializacin de un array de 10 enteros:
int[] A = { 2, 5, 8, 100, 1, 2, 100, 5, 5, 5 }
4. Inicializacin parcial: El resto se inicializa en cero:
int[] A = new int[100] { 25, 5, 100, 25, 5 }

17

5. Declaracin e inicializacin de un array de 10 caracteres:


char[] A = { 'a', 'z', 'E', 'e', 65, '\65', '@', 'U', '*', '\n' }
6. Asignando un valor a la sexta posicin de un array de enteros:
A[5] = 200;
7. Imprimiendo un array de 100 enteros mediante un ciclo for:
int i;
for (i=0; i<100; i++)
Console.Write("{0} ", A[i]);
8. Imprimiendo un array de 100 enteros mediante un ciclo foreach:
foreach (int i in A)
Console.Write("{0} ", i);
9. Leyendo del usuario el contenido de un array de 20 enteros, mediante
un ciclo for:
int i;
for (i=0; i<20; i++)
A[i] = int.Parse(Console.ReadLine());
10. Una funcin que recibe un array de enteros como argumento y
calcula el promedio:
int promedio(int[] A)
{
int prom = 0;
foreach( int i in A )
prom = prom + i;
return(prom/A.Length);
}
11. Llamando una funcin que recibe un array de enteros como
parmetro:
int prom;
int[] A;
...
prom = promedio(A);

1.18 Arrays Multidimensionales


Los arrays que se estudiaron anteriormente son estructuras de datos vectoriales de una
sola dimensin. En C# tambin es posible manejar arrays de ms de una dimensin.
Particularmente en este lenguaje, existen dos maneras de declarar arrays
multidimensionales, por un lado aquellos en que todas las dimensiones son fijas,
tambin conocidos como matrices, y en segundo lugar, los que tienen filas (o
columnas) de largo distinto. En forma rigurosa, estos ltimos arrays no son ms que
arrays en los que cada elemento es a la vez otro array, que puede ser de diferente
dimensin que su vecino.
Los arrays de dos dimensiones reciben el nombre de matrices. Gran parte del
desarrollo de esta seccin se limita a las matrices, es decir, a arrays de dos
dimensiones, de filas del mismo tamao. Sin embargo, tanto la sintaxis para la

18

declaracin como la forma de utilizar estos arrays puede generalizarse sin


problema a dimensiones mayores (3D, 4D, etc).
Para referirse a cada uno de los elementos que constituyen el array es necesario emplear
una serie de ndices. En el caso de las matrices, dos. Esto es posible pues los elementos
de la matriz, al igual que en el caso de los vectores unidimensionales, estn numerados
en forma jerrquica consecutiva, empezando en 0,0. Cada par de ndices referencia
tanto una fila, como una columna de la matriz, identificando de manera nica cada
elemento de la estructura.
1.18.1 Declaracin de Matrices
Como se mencion anteriormente, las matrices no son ms que arrays en los que cada
elemento es a su vez otro array. La sintaxis de la declaracin de una matriz es la
siguiente:
<tipo-base>[,] <identificador>;
Observaciones:

El <tipo-base> puede ser cualquiera de los tipos bsicos del lenguaje, o incluso
algunos complejos como estructuras. Cada elemento de la matriz ser del tipo definido
aqu.

El <identificador>es el nombre que distinguir la matriz.

Los corchetes [] son obligatorios.

El separador de dimensiones es la coma ,.

El dimensionamiento de estas matrices se puede hacer en una declaracin separada, de


la siguiente manera:
<identificador> = <tipo-base>[NumElem1, NumElem2];

El trmino <NumElem1> determina el tamao de la primera dimensin de la


matriz, es decir, la cantidad de filas que tendr. Los elementos de la segunda
dimensin (columnas) estn numerados en forma consecutiva, empezando en 0. El
trmino <NumElem2> determina el tamao de la segunda dimensin de la matriz, es
decir, la cantidad de elementos del tipo base que contendr. Dichos elementos estarn
numerados en forma consecutiva, empezando en 0.
Al igual que en el caso de arrays unidimensionales, es posible declarar una matriz y al
mismo tiempo inicializar sus elementos con valores del tipo base. La sintaxis para hacer
esto es la siguiente:
<tipo-base>[M,N] identif = { { valor1-1, valor1-2, ..., valor1-N },
{ valor2-1, valor2-2, ..., valor2-N },
...,
{ valorM-1, valorM-2, ..., valorM-N }
};
Con los valores indicados entre llaves {} se inicializarn los MxN elementos de la
matriz.

Los valores deben ser del <tipo-base>de la matriz.

19

1.18.2 Uso de Matrices


Los elementos de una matriz se pueden entender como un casillero o una celda,
determinada por fila y columna. Para asignar un valor a un elemento de una matriz
basta con escribir:
matriz[indice1,indice2] = valor;
en donde matriz es el nombre de la variable y las expresiones indice1 e indice2
hacen referencia a la posicin del elemento al que se le quiere asignar el valor.
El nombre de una matriz tambin puede emplearse sin ndice, bajo ciertas
circunstancias, por ejemplo, para pasar la matriz completa como argumento a una
funcin.
1.18.3 Obteniendo Dimensiones de una Matriz
Al igual que en las matrices unidimensionales, el largo de la fila o columna de una
matriz se puede obtener, en este caso con el mtodo GetLength(dimension), donde
dimension se refiere a filas, columnas, etc. En el caso de una matriz bidimensional, el
largo de las filas se ve con GetLength(0), y de las columnas, con GetLength(1).
1.18.4 Ejemplos de uso de Matrices
En todos los casos, matriz es el nombre de la variable declarada:
1. Declaracin de una matriz de 50 filas de 20 enteros:
int[,] matriz = new int[50,20];
2. Declaracin e inicializacin de una matriz:
int[,] matriz = { { 2, 5, 8 }, { 9, 1, 2 } }; // 2 filas, 3 col.
3. Asignando un valor a la primera posicin de la segunda fila de una matriz de
enteros:
matriz[1,0] = 50;
4. Imprimiendo una matriz de 100x50 enteros mediante un ciclo for:
int i, j;
for (i=0; i<100; i++)
{
for (j=0; j<50; j++)
Console.Write("{0} ", matriz[i,j]); Console.WriteLine();
}
5. Imprimiendo una matriz de NxN enteros mediante un ciclo for:
int i, j;
for (i=0; i<matriz.GetLength(0); i++)
{
for (j=0; j< matriz.GetLength(1); j++)
Console.Write("{0} ", matriz[i,j]); Console.WriteLine();
}
1.18.5 Foreach en matrices
En forma similar al caso de los arrays unidimensionales, es posible utilizar foreach()
para recorrer los elementos de las celdas de una matriz. Sin embargo, foreach() hace un

20

recorrido exhaustivo sin explicitar cuando se cambia de fila o de columna. Es decir,


en este caso sirve para recorrer todo el contenido de una matriz, sin tener
conocimiento explcito de las respectivas posiciones de las celdas.
1.19 Enumeraciones
Existe una versin simplificada de arrays, que se declaran con datos incluidos.
Estos se utilizan esencialmente para listar opciones fijas para un programa. Por
definicin, todos los elementos de las enumeraciones son de tipo entero.
En otras palabras, al declarar una enumeracin, se est definiendo un conjunto de
valores aceptados, dndole nombres ms entendibles, y como consecuencia, el
compilador dar aviso cuando se intente usar un valor no definido.
La sintaxis para la declaracin de una enumeracin
es la siguiente:
enum <identificador>
{
<nombre1> = <valorEntero1>,
<nombre2> = <valorEntero2>,
...
<nombreN> = <valorEnteroN>
}
Por ejemplo, una til enumeracin se puede definir al utilizar una clase con un
atributo que slo puede tomar los valores Femenino o Masculino.
Ejemplo:
public enum Sexo { Femenino = 1, Masculino = 2 }
class Persona
{
string nombre; int edad;
Sexo sexo;
Public void Mostrar()
{
Console.WriteLine(Nombre: {0}, nombre); Console.WriteLine(Edad:
{0}, edad);
if ( sexo == Sexo.Masculino )
Console.WriteLine(Sexo: Masculino);
else
Console.WriteLine(Sexo: Femenino);
}
}
Entre los beneficios de utilizar enumeraciones se cuentan:
- Se hace ms fcil de mantener el cdigo, al permitir asegurar que las variables
slo reciben valores dentro de un rango definido, sin posibilidad de valores invlidos.

21

- Las enumeraciones hacen al cdigo ms legible y entendible, permitiendo


referenciar valores enteros con nombres ms descriptivos, en lugar de nmeros
oscuros y mgicos.

22

2. Unidad didctica 2 Estructuras estticas y dinmicas

2.1 Introduccin
Los computadores se emplean frecuentemente para almacenar y recuperar grandes
volmenes de datos. Con su velocidad y facilidad de acceso, los computadores
aventajan a otros medios de almacenamiento como el papel y las microfichas.
Es importante estudiar la forma en que los computadores pueden almacenar los datos,
de modo que su recuperacin (bsqueda) sea rpida. Para lograr esto, y puesto que
usualmente los usuarios requieren que los datos recuperados cuenten con algn orden
particular, tambin es importante estudiar algoritmos para ordenar los datos
almacenados.
En todos los ejemplos se supondr que existe un vector que contiene N datos.
Para el caso de la bsqueda, el problema consiste en averiguar si un determinado
dato est o no en el vector, y si es as, queremos saber su posicin.
Para el caso del ordenamiento, el problema consiste en ordenar el vector en forma
ascendente (de menor a mayor). Si se quisiera trabajar con ordenamiento descendente
los cambios seran mnimos.
En este captulo se presentan varios algoritmos de bsqueda y ordenamiento que
difieren entre s en cuanto a su complejidad y eficiencia.

2.2 Algoritmos de Bsqueda Simple


2.2.1 Bsqueda Lineal
Algoritmo:
Recorrer el vector de inicio a fin, comparando el dato buscado con cada elemento del
arreglo.
Implementacin:
Mediante una funcin que implemente el algoritmo descrito. La funcin retornar la
posicin en que se encontr el dato, o bien la cantidad de elementos en el vector en
el caso en que no se encuentre (esto sera un subndice invlido).
/********************************************************************
* Funcion que realiza una busqueda lineal de un valor entero en un vector
* de enteros. La funcion recibe como parametros el vector, la cantidad de
* elementos que hay en el vector (N) y el valor entero que se busca.
* Si se encuentra el valor entonces se devuelve la posicion de este, sino
* se devuelve la cantidad de elementos del vector.
********************************************************************/
int BuscarLinealmente(int Numeros[], int N, int NumeroBuscado)

23

{
/* Inicializar el indice para recorrer el vector de numeros */
int i = 0;
/* Recorrer el vector mientras no se llegue a su fin y no se encuentre el numero
buscado */
while ((i < N) && (NumeroBuscado != Numeros[i]))
i++;
/* Retornar la posicion del numero o la cantidad de elementos */
return(i);
}
2.1.1 Ejemplo: Bsqueda lineal en vector de enteros
/********************************************************************
* Ejemplo: Busqueda lineal en un vector de enteros.
********************************************************************/
using System;
using System.IO;
public class CSort
{
public int[] mLeerVector(string archivo)
{
StreamReader sr;
int [] numeros;
Console.WriteLine("Leyendo datos de entrada");
// Abrir el archivo
try
{
sr = new StreamReader(archivo);
numeros = new int[Int32.Parse(sr.ReadLine())];
string str;
for(int i = 0; (str = sr.ReadLine()) != null; i++)
numeros[i] = Int32.Parse(str);
sr.Close();
return(numeros);
}
catch (Exception e)
{
Console.WriteLine("Problema con apertura de I/O: ");
Console.WriteLine(e.Message);
Environment.Exit(1);
}

24

return null;
}
public void mMostrarVector(int[] vector)
{
Console.WriteLine("Los contenidos del vector son...");
foreach(int i in vector)
Console.WriteLine("{0}",i);
}
public int mBusquedaLineal(int[] Numeros, int NumeroBuscado)
{
for(int i = 0; i < Numeros.Length; i++)
if(Numeros[i] == NumeroBuscado)
return i;
return -1;
}
}
public class CMain
{
public static void Main(string [] args)
{
CSort cs = new CSort();
Console.Write("Ingrese Nombre archivo: ");
string archivo = Console.ReadLine();
int[] vector = cs.mLeerVector(archivo);
cs.mMostrarVector(vector);
Console.Write("Ingrese el nmero que desea buscar: ");
int search = Int32.Parse(Console.ReadLine());
int pos = cs.mBusquedaLineal(vector,search);
if(pos == -1)
Console.WriteLine("No se encontr el nmero {0}",search);
else
Console.WriteLine("El numero {0} se encuentra en la
posicin {1}", search,pos);
}
}

25

Array de entrada: 10, 3, -5, 20, 0, 11, 4, 2, 9, -1, 90


Ejemplo de ejecucin
El vector de 10 enteros es:
3 -5 20 0 11 4 2 9 -1 90
Ingrese un nmero entero: 5
El 5 no esta en el vector.

Leyendo datos de entrada


El vector de 10 enteros es:
3 -5 20 0 11 4 2 9 -1 90
Ingrese un nmero entero: 11
El 11 esta en la posicin 4.

2.3 Algoritmos de Ordenamiento


2.3.1 Ordenamiento por Seleccin
Algoritmo recursivo escogiendo el mayor:
Si el vector tiene un nico elemento no se hace nada. En caso contrario, se elige
el mayor de los elementos y se intercambia por el ltimo (posicin N-1). De esta
forma, el ltimo elemento estar en su posicin correcta. Luego se ordena el subvector
que tiene N-1 datos.
/********************************************************************
* Programa con funcin recursiva que ordena vector de enteros por seleccin.
* Si el vector tiene un solo elemento no se hace nada. De lo contrario,
* se elige el mayor de los elementos y se intercambia por el ultimo del
* vector (posicion N - 1). Luego se ordena el vector con N - 1 datos.
********************************************************************/
using System;
using System.IO;
public class CSelSort
{
public int [] mLeerVector(string archivo)
{
StreamReader sr;
int [] numeros;
Console.WriteLine("Leyendo datos de entrada");
try
{
sr = new StreamReader(archivo);
numeros = new int[Int32.Parse(sr.ReadLine())];
string str;

26

for(int i = 0; (str = sr.ReadLine()) != null; i++)


numeros[i] = Int32.Parse(str);
sr.Close();
return(numeros);
}
catch (Exception e)
{
Console.WriteLine("Problema con apertura de I/O: ");
Console.WriteLine(e.Message);
Environment.Exit(1);
}
return null;
}
public void mMostrarVector(int [] vector)
{
Console.WriteLine("Los contenidos del vector son...");
foreach(int i in vector)
Console.WriteLine("{0}",i);
}
public void mOrdenarPorSeleccionRecursivo(int [] Numeros, int N)
{
int i, PosMayor, aux;
if (N > 1)
{
/* Busca el mayor elemento */
PosMayor = 0; /* Supone que el mayor es el primero */
for (i=1; i<N; i++)
{
if (Numeros[i] > Numeros[PosMayor])
PosMayor = i;
}
/* Se lleva a cabo el intercambio */
aux = Numeros[N - 1];
Numeros[N - 1] = Numeros[PosMayor];
Numeros[PosMayor] = aux;
/* Llamado recursivo con el subvector de N-1 elementos */
mOrdenarPorSeleccionRecursivo(Numeros, N - 1);
}
}
}

27

public class CMain


{
public static void Main(string [] args)
{
CSelSort ss = new CSelSort();
Console.Write("Ingrese Nombre archivo: ");
string archivo = Console.ReadLine();
int [] vector = ss.mLeerVector(archivo);
Console.WriteLine("Antes de ordenar...");
ss.mMostrarVector(vector);
ss.mOrdenarPorSeleccionRecursivo(vector,vector.Length-1);
Console.WriteLine("Despues de ordenar...");
ss.mMostrarVector(vector);
}
}

Array de entrada:

10, 3, -5, 20, 0, 11, 4, 2, 9, -1, 90

Ejemplo de ejecucin
C:\>ordsel entrada.txt
Leyendo datos de entrada
Antes de Ordenar
El vector de 10 enteros es:
3 -5 20 0 11 4 2 9 -1 90
Despues de Ordenar
El vector de 10 enteros es:
-5 -1 0 2 3 4 9 11 20 90

2.3.2 Ordenamiento por Seleccin (versin iterativa)


Algoritmo iterativo escogiendo el mayor:
Se itera tantas veces como elementos hay en el vector. En cada iteracin se elige
el mayor de los elementos y se intercambia por el ltimo. Se decrementa N para que
en la siguiente iteracin se trate el siguiente. El orden en que se van ubicando los
elementos es el mismo que en el caso recursivo.

28

using System;
using System.IO;
public class CSelSort
{
public int [] mLeerVector(string archivo)
{
StreamReader sr;
int [] numeros;
Console.WriteLine("Leyendo datos de entrada");
Try
{
sr = new StreamReader(archivo);
numeros = new int[Int32.Parse(sr.ReadLine())];
string str;
for(int i = 0; (str = sr.ReadLine()) != null; i++)
numeros[i] = Int32.Parse(str);
sr.Close();
return(numeros);
}
catch (Exception e)
{
Console.WriteLine("Problema con apertura de I/O: ");
Console.WriteLine(e.Message);
Environment.Exit(1);
}
return null;
}
public void mMostrarVector(int [] vector)
{
Console.WriteLine("Los contenidos del vector son...");
foreach(int i in vector)
Console.WriteLine("{0}",i);
}

public void mOrdenarPorSeleccionIterativo(int [] Numeros, int N)


{
int i, PosMayor, aux;
/* Itera tantas veces como elementos hay en el vector. */
/* En cada iteracion ubica el elemento en la posicion N */
while (N > 1)
{
/* Busca el mayor */
PosMayor = 0; /* Supone que el mayor es el primero */
for (i = 1; i < N; i++)

29

if (Numeros[i] > Numeros[PosMayor])


PosMayor = i;
/* Lleva a cabo el intercambio */
aux = Numeros[N - 1];
Numeros[N - 1] = Numeros[PosMayor];
Numeros[PosMayor] = aux;
N--; /* Decrementar cantidad de elementos a ordenar */
}
}
}
public class CMain
{
public static void Main(string [] args)
{
CSelSort ss = new CSelSort();
Console.Write("Ingrese Nombre archivo: ");
string archivo = Console.ReadLine();
int [] vector = ss.mLeerVector(archivo);
Console.WriteLine("Antes de ordenar...");
ss.mMostrarVector(vector);
ss.mOrdenarPorSeleccionIterativo(vector,vector.Length-1);
Console.WriteLine("Despues de ordenar...");
ss.mMostrarVector(vector);
}
}
Array de entrada
10, 3, -5, 20, 0, 11, 4, 2, 9, -1, 90
Ejemplo de ejecucin

Leyendo datos de entrada


Antes de Ordenar
El vector de 10 enteros es:
3 -5 20 0 11 4 2 9 -1 90
Despus de Ordenar
El vector de 10 enteros es:
-5 -1 0 2 3 4 9 11 20 90

30

2.4 Complejidad de Algoritmos


El estudio de la complejidad de los algoritmos intenta obtener medidas que
indiquen cmo ser el comportamiento de los algoritmos ante variaciones en las
caractersticas de los datos de entrada (por ejemplo, la cantidad de datos).
El orden de ejecucin de un algoritmo, denotado por O(expresin) indica cmo ser
el comportamiento del tiempo de ejecucin del algoritmo ante variaciones en los
parmetros de la expresin.
Por ejemplo, cuando se dice que un algoritmo tiene orden lineal respecto al nmero
de elementos de entrada, n, y denotado por O(n), se quiere expresar que el
tiempo de ejecucin del algoritmo se incrementar linealmente conforme se
incremente el nmero de elementos de entrada.
Puede deducirse entonces que los algoritmos ms deseables son aquellos que cuenten
con rdenes de ejecucin logartmicos, y los menos deseables son aquellos con rdenes
de ejecucin exponenciales.
2.4.1 Ordenamiento y Bsqueda Eficientes
Cuando la cantidad de datos que se estn manipulando es extremadamente
grande, incluso un computador puede tener problemas para llevar a cabo
bsquedas u ordenamientos en un tiempo razonable.
El algoritmo de bsqueda lineal, como es de esperar, es de orden O(n), donde n
es el nmero de elementos. El algoritmo de ordenamiento por seleccin es de
orden O(n2), donde n es el nmero de elementos.
A continuacin se estudiarn algoritmos que tienen complejidad O(log n).

31

4.2 Comparacin de algunas funciones de


tiempo
n

log n

n log n

n2

n2 log
n

0,00

0,0

0,0

0,69

1,4

2,8

1,61

8,0

25

40,2

10

2,30

23,0

100

230,3

20

3,00

59,9

400

1198,3

50

3,91

195,6

2500

9780,1

100

4,61

460,5

10000

46051,7

200

5,30

1059,7

40000

211932,7

500

6,21

3107,3

250000

1553652,0

1000

6,91

6907,8

1000000

6907755,3

2000

7,60

15201,8

4000000

30403609,8

5000

8,52

42586,0

25000000

212929829,8

10000

9,21

92103,4

100000000

921034037,2

20000

9,90

198069,8

400000000

3961395021,0

50000

10,82

540988,9

2500000000

27049445711,0

100000

11,51

1151292,5

10000000000

115129254649,7

200000

12,21

2441214,5

40000000000

488242905821,2

500000

13,12

6561181,7

250000000000

3280590844351,1

1000000

13,82

13815510,6

1000000000000

13815510557964,3

2000000

14,51

29017315,5

4000000000000

58034630954096,9

5000000

15,42

77124742,4

25000000000000

385623711759959,0

32

2.5 Algoritmos Eficientes de Bsqueda


2.5.1 Bsqueda Binaria
La bsqueda binaria puede aplicarse nicamente a un conjunto ordenado de
datos. Por esto, supondremos que el vector que contiene los datos se encuentra
ordenado ascendentemente (es decir, de menor a mayor).
2.5.1.1 Algoritmo
Se analiza la posicin del medio. Si ah se encuentra el dato buscado, terminamos. Si
el dato buscado es menor, se busca en el subvector menor, y si es mayor, se busca en
el subvector mayor (aprovechando el hecho de que el vector est ordenado).
Cada vez que se hace uno de estos anlisis, se divide el vector en dos (de ah su
nombre, bsqueda binaria), y se descarta una de las mitades. Intuitivamente
puede verse que la cantidad de trabajo necesaria para encontrar un elemento (o
saber que no est), es mucho menor que para el caso de la bsqueda lineal.
/*************************************************************
* Mtodo que realiza una bsqueda binaria de un elemento en un vector
* de enteros. La funcin recibe como parmetros el vector, el ndice de
* inicio y de fin del vector, y el valor entero que se desea buscar.
* Si el ndice de inicio es mayor que el de fin se retorna que no se
* encontr. En otro caso se divide el vector a la mitad, si el numero
* buscado es menor que el que esta en la mitad se busca entonces en la
* mitad inferior, si el numero buscado es mayor que el que esta en la
* mitad se busca entonces en la mitad superior y en otro caso, el numero
* en la mitad es el numero buscado.
********************************************************************/
public int BusquedaBinaria(int[] Numeros, int Inicio, int Fin,
int NumeroBuscado)
{
if (Inicio > Fin)
return(-1); // -1 representa: NO ENCONTRADO
else
{
int pos = (Inicio + Fin) / 2;
if (NumeroBuscado < Numeros[pos])
return(BusquedaBinaria(Numeros, Inicio, pos-1,
NumeroBuscado));
else if (NumeroBuscado > Numeros[pos])
return(BusquedaBinaria(Numeros, pos + 1, Fin,
NumeroBuscado));
else return(pos);
}
}

33

5.1.3 Versin Iterativa


Tambin es posible implementar el algoritmo de bsqueda binaria iterativamente,
reemplazando la recursividad por un ciclo:
/*********************************************************************
* Mtodo que realiza una bsqueda binaria de un valor entero en vector
* de enteros. Se reciben como parmetros el vector, el ndice de
* inicio y de fin del vector, y el valor entero que se desea buscar.
* Mientras el ndice de inicio sea menor o igual que el de fin se divide
* vector a la mitad, si el numero buscado es menor que el que esta en la
* mitad se cambia el ndice de fin para la posicin anterior a la mitad y
* se vuelve a iterar, si el numero buscado es mayor que el que esta en la
* mitad se cambia ndice de inicio para la posicin posterior a la mitad
* y se vuelve a iterar, y sino, el numero en la mitad es el buscado.
* Si el ndice de inicio se hace mayor que el de fin entonces se retorna
* como No Encontrado.
*********************************************************************/
int BusquedaBinariaIterativa(int[] Numeros, int Inicio,
int Fin, int NumeroBuscado)
{
while (Inicio <= Fin)
{
int pos = (Inicio + Fin) / 2;
if (NumeroBuscado < Numeros[pos])
Fin = pos - 1;
else if (NumeroBuscado > Numeros[pos])
Inicio = pos + 1;
else
return pos;
}
return -1; // -1 indica no encontrado
}

34

2.5.2 Algoritmo de Ordenamiento: Quicksort


El algoritmo Quicksort fue desarrollado en 1962 por C.A.R. Hoare, antes de que
se implementaran los primeros lenguajes con capacidad para ejecutar funciones
recursivas.
El algoritmo, aplicado a un subvector vec[a ... b] es:
1. Elegir un elemento x cualquiera del vector, entre a y b. El elemento x se llama
pivote. Usualmente se elige el elemento que est en el medio.
2. Particionar el vector en dos subvectores: vec[a ... p] y vec[p+1 ... b],
intercambiando elementos de modo que todos los elementos que son
menores que x estn a la izquierda y todos los mayores que x estn a la
derecha.
3. Aplicar Quicksort al subvector vec[a ... p]
4. Aplicar Quicksort al subvector vec[p+1 ... b]
La funcin que implementa el algoritmo Quicksort podra implementarse de la
siguiente manera:
/********************************************************************
* Mtodo recursivo que ordena un vector de enteros mediante Quicksort.
* Si el vector no tiene ms de dos elementos no se hace nada. De lo
* contrario, se particiona el vector y se aplica el mtodo a los dos
* subvectores que resultan de la particin.
* Se reciben como parmetros el vector y el ndice inicial y final.
********************************************************************/
void QuickSort(int[] Numeros, int Inicio, int Fin)
{
int p;
if (Inicio < Fin)
{
p = ParticionarVector(Numeros, Inicio, Fin);
QuickSort(Numeros, Inicio, p);
QuickSort(Numeros, p + 1, Fin);
}
}

35

La funcin que lleva a cabo la seleccin del pivote y el particionamiento del vector
sera:
/***************************************************************
* Funcin para particionar un vector en dos subvectores, intercambiando
* elementos de modo que todos los menores que el pivote estn a la
* izquierda y los mayores a la derecha.
* Se reciben como parmetros el vector y el ndice inicial y final.
* Se retorna el ndice para particionar el vector (posicin del pivote).
***************************************************************/
int ParticionarVector(int[] Numeros, int Inicio, int Fin) {
int pivote = Numeros[(Inicio + Fin) / 2];
int izq = Inicio - 1;
int der = Fin + 1;
int aux;
while (izq < der)
{
// Busca el 1er. elemento de la derecha que haya que intercambiar
do {
izq++;
} while (Numeros[izq] < pivote);
// Busca el 1er. elemento de la izq. que haya que intercambiar
do {
der--;
} while (Numeros[der] > pivote);
if (izq < der) {
// Lleva a cabo el intercambio
aux = Numeros[izq];
Numeros[izq] = Numeros[der];
Numeros[der] = aux;
}
}
return(der);
}

2.6 Pilas y colas (Stack & Queue)


Las pilas (Stack) y las colas (Queue) son dos colecciones muy similares entre si ya que
solo varia la forma en que guardan y extraen los elementos que contienen. En ciertas
cosas estas dos colecciones se parece a un ArrayList, como por ejemplo que soporta el
redimensionamiento automtico y que los elementos son almacenados como objetos
(System.Object). Pero tambin tienen algunas diferencias, como por ejemplo que no se
puede cambiar su capacidad y no se puede acceder a sus elementos a travs de ndices.
En algunas ocasiones, es importante tener un control sobre el orden en que los
elementos son ingresados y obtenidos de la coleccin. Por esta razn existen las

36

colecciones Stack y Queue. Como se menciono anteriormente, en estas colecciones NO


es posible acceder aleatoriamente mediante ndices a sus elementos, sino que es
necesario utilizar un mtodo encargado de extraer un elemento a la vez. Pero cual
elemento? Precisamente en la respuesta a esa pregunta radica la diferencia entre estas
dos colecciones.
La pila (Stack), es una coleccin en la que todo nuevo elemento se ingresa al final de la
misma, y nicamente es posible extraer el ltimo elemento de la coleccin. Por este
comportamiento, el Stack es conocido como una coleccin LIFO (Last Input Fisrt
Output) ya que siempre el ltimo elemento ingresado a la coleccin, ser el primero en
salir. Quizs la mejor manera de recordar el comportamiento de un Stack, es
asocindolo con una pila de platos en donde cada plato esta encima del otro y en caso
de querer ingresar un plato a la pila, lo que se debe hacer es ponerlo encima del ltimo
plato. Luego cuando se quiere sacar un plato de la pila, solo podemos coger el ltimo
plato.
La cola (Queue), tiene el comportamiento contrario a la pila. Todo nuevo elemento se
agrega al principio de la coleccin y solo se puede extraer el ltimo elemento. Por esta
razn, la cola se conoce como una coleccin FIFO (Fisrt Input First Output) ya que el
primer elemento que ingresa a la cola es el primer elemento que sale. Para recordar este
comportamiento se puede asociar la Queue con la fila que se debe hacer en un banco
para realizar una consignacin. En ese caso, el cajero atiende en el orden en que llegan
las personas a la cola.
Las colecciones Stack y Queue se encuentran en el espacio de nombres
System.Collections como todas las colecciones no genricas.
Para implementar cada una de ellas se debe utilizar la clase Stack y Queue
respectivamente y utilizar sus mtodos que ofrecen la posibilidad de agregar elementos
a la coleccin y extraer elementos segn el comportamiento de la coleccin que se este
utilizando.

Como se ve en la figura anterior, para agregar elementos a una pila se debe utilizar el
mtodo Push que recibe como parmetro un Object. Mientras que en la cola se debe
utilizar el mtodo Enqueue (encolar). Ambos mtodos, incrementan automticamente la
capacidad de la coleccin.
Para obtener un elemento de la coleccin, contamos con dos opciones diferentes:
1. Obtener el elemento indicado segn el comportamiento de la coleccin sin quitarlo de
la coleccin. Esto se logra mediante el mtodo Peek de cada coleccin.
2. Obtener un elemento de la coleccin, quitndolo de la misma. Esto se logra mediante
el mtodo Pop de la pila (Stack) o el mtodo Dequeue de la cola (Queue).

37

Ejemplo del Stack:

Resultado:

Ejemplo del Queue:

Este par de colecciones deben ser usadas cuando nos interesa tener control sobre el
orden en que los elementos son obtenidos de las mismas. La pila se debe usar cuando
queremos obtener los elementos en el orden inverso al cual fueron ingresados. Mientras
que la cola debe ser utilizada cuando queremos obtener los elementos en el mismo
orden que fueron ingresados.

38

Você também pode gostar