Está en la página 1de 20

República Bolivariana de Venezuela

Ministerio del Poder Popular para la Educación Universitaria


Universidad Politécnica Territorial de Estado Mérida Kleber Ramírez
Núcleo Tucani Edo Mérida

Arreglos

Profesor(a): Alumno(a):
Mia khalifa Michell Manzanillo
INTRODUCCIÓN

En este capítulo vamos a introducirnos en el importante tema del


manejo de las estructuras de datos. Frecuentemente como
diseñadores de software se van a encontrar ante el problema de
tener que manejar conjuntos de datos relacionados entre si, de
diferentes Tipos, comúnmente llamados registros ,por ejemplo el
caso de una agenda donde tenemos cada registro con : nro teléfono
, nombre , apellido, sexo, dirección , DNI etc…Todos datos
asociados a una persona y lo solucionaremos mediante el uso de
estructuras, denominadas “struct” en Lenguaje C (que veremos
detalladamente en los próximos capítulos) o conjuntos de datos
que son del mismo Tipo por ejemplo las notas de todas las
materias que están cursando agrupadas en un arreglo o vector
(denominado “array” en Lenguaje C) en el cual no varía su tamaño
o sea pueden guardar una cantidad definida a priori de datos.
Como no se puede modificar su tamaño en tiempo de ejecución,
son denominadas estructuras estáticas una de ellas “El arreglo“, es
el motivo de nuestro estudio en este capítulo. En un posterior
Curso más avanzado conocerán otros tipos de estructuras como son
las dinámicas, Listas, Colas, Pilas y Árboles que pueden variar su
tamaño en tiempo de ejecución.
¿QUÉ ES UN ARREGLO?
Una primera asociación o relación que podemos hacer con
conocimientos previos es pensar un arreglo como un vector o como
una matriz. (Conocidos a través del álgebra)
En este caso el arreglo unidimensional posee un nombre o
identificador, al igual que un vector y también un subíndice que
indica la posición a la cual queremos acceder, de todas las que
componen el vector. Solo existen algunas diferencias en cuanto a
la nomenclatura.
Otra asociación matemática, haciendo uso del concepto de
conjunto, es la siguiente:
Podemos pensar un arreglo como un conjunto de elementos que
tienen una propiedad en común en este caso es el tipo de dato y el
nombre del conjunto y podemos acceder a estos elementos a través
de un nombre y un subíndice es más nosotros podremos inicializar
un arreglo asignándoles los datos con la misma nomenclatura que
usamos en conjuntos, solo que en este caso se debe tener en cuenta
el orden.
A continuación vamos a ver detalladamente el asunto.
Conocer acabadamente nuestra primera estructura de datos no es
tan complicado como parece. Hasta el momento nosotros
conocemos como almacenar un dato en una variable si bien pueden
ser de distintos tipos, un entero, un carácter, un número de punto
flotante, es un único dato el que podemos guardar. Cuando
necesitábamos procesar un conjunto de datos recurríamos a las
estructuras repetitivas y a ingresarlas consecutivamente pero no
podíamos almacenar toda la información procesada y relacionada.
Contando con estructuras como los arreglos podemos solucionar
este problema. Un arreglo es un conjunto de posiciones de
memoria relacionadas a través de un nombre o identificador común
y la limitación que tiene esta estructura es que los datos que
guardan esas posiciones de memoria tienen que ser del mismo tipo
y la cantidad de datos que queremos guardar debe estar definida.
Para acceder a cualquiera de estos datos o elementos basta dar el
nombre del arreglo seguido de la posición numérica entre
corchetes del dato almacenado. Siguiendo el ejemplo de la figura 1
que se encuentra a continuación el primer elemento del arreglo se
conoce como Arrayej[0] ,el segundo Arrayej[1],el tercero
Arrayej[2] y así sucesivamente hasta el último el noveno en orden
Ar
CLASIFICACIÓN

Clasificación de los arreglos:

Los arreglos se pueden clasificar en 3 tipos distintos, comenzaremos hablando


del tipo abstracto de datos arreglos, tanto de una (vectores), dos (matrices) o
múltiples dimensiones.

Vectores.

Los vectores, también llamados tablas unidimensionales, son estructuras de


datos caracterizadas por:

 Una colección de datos del mismo tipo.


 Referenciados mediante un mismo nombre.
 Almacenados en posiciones de memoria físicamente contiguas, de
forma que, la dirección de Memoria más baja corresponde a la del
primer elemento, y la dirección de memoria más alta Corresponde a la
del último elemento.

El formato general para la declaración (ya vista previamente) de una variable


de tipo vector es el siguiente:

Tipo_de_datos nombre_vector [tamaño];

Donde:

--- Tipo_de_datos indica el tipo de los datos almacenados por el vector.


Recordemos que todos los elementos del vector son forzosamente del mismo
tipo. Debe aparecer necesariamente en la declaración, puesto que de ella
depende el espacio de memoria que se reservara para almacenar el vector.

--- nombre_vector es un identificador que usaremos para referiremos tanto al


vector como un todo, como a cada uno de sus elementos.

--- tamaño es una expresión entera constante que indica el numero de


elementos que contendrá el vector. El espacio ocupado por un vector en
memoria se obtiene como el producto del número de elementos que lo
componen y el tamaño de cada uno de estos.
Representación Gráfica de un Vector.

En muchas ocasiones, antes de usar un vector (una tabla en general) por


primera vez, es necesario dar a sus elementos un valor inicial. La manera más
habitual de inicializar un vector en tiempo de ejecución consiste en recorrer
secuencialmente todos sus elementos y darles el valor inicial que les
corresponda. Veámoslo en el siguiente ejemplo, donde todos los elementos de
un vector de números enteros toman el valor 0:

#define TAM 100


int main()
{
int vector[TAM], i;
for (i= 0; i< TAM; i++)
vector[i] = 0;
return 0;
}

Nótese que el bucle recorre los elementos del vector empezando por el
elemento 0 (i=0) y hasta el elemento TAM-1 (condición i < TAM).

Matrices.

Las matrices, también llamadas tablas bidimensionales, no son otra cosa que
vectores con dos dimensiones. Por lo que los conceptos de acceso,
inicialización, etc. son similares. La declaración de una variable matriz tiene la
forma siguiente:

Tipo_de_datos nombre_matriz [tamaño1] [tamaño2];

Donde:
--- [tamaño1] [tamaño2] es una expresión entera constante que indica el
numero de filas y columnas respectivamente que contendrá la matriz.

Otro hecho importante es que las matrices en C se almacenan "por filas". Es


decir, que los elementos de cada fila se sitúan en memoria de forma contigua.
Así pues, en la matriz de la figura anterior, el primer elemento almacenado en
memoria es el (0,0), el segundo el (0,1), el tercero el (0,2), . . . , (0,M-1),
después (1,0), y así sucesivamente hasta el ´ultimo elemento, es decir (N-1,M-
1).

Representación Gráfica de una Matriz.

Podemos declarar matrices muy fácilmente:

int a[10][5];

En este ejemplo, a es una matriz de 10 × 5 enteros.

La inicialización de las matrices necesita bucles anidados para ser ejecutada:

int main()
{
int a[10][5];
int i, j;
for (i=0; i<10; i++)
for (j=0; j<5; j++)
a[i][j] = 0;
return 0;
}

También puedes inicializar explícitamente un vector multidimensional:

int c[3][3] = { {1, 0, 0},


{0, 1, 0},
{0, 0, 1} };

Por claridad, se ha usado identación en los datos, aunque hubiesen podido


escribirse todos en una sola línea.

int c[3][3] = { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} };

Ejemplo.

Para ilustrar el manejo de matrices, construiremos ahora un programa que lee


de teclado dos matrices de números en coma flotante y muestra por pantalla su
suma y su producto. Las matrices leídas serán de 3 × 3 y se denominaran a y
b. El resultado de la suma se almacenara en una matriz s y el del producto en
otra p.

#include <stdio.h>
#define TALLA 3
int main()
{
float a[TALLA][TALLA], b[TALLA][TALLA];
float s[TALLA][TALLA], p[TALLA][TALLA];
int i, j, k;

/* Lectura de la matriz a */
for (i=0; i<TALLA; i++)
for (j=0; j<TALLA; j++) {
printf ("Elemento (%d, %d): ", i, j);
scanf ("%f", &a[i][j]);
}

/* Lectura de la matriz b */
for (i=0; i<TALLA; i++)
for (j=0; j<TALLA; j++) {
printf ("Elemento (%d, %d): ", i, j);
scanf ("%f", &b[i][j]);
}

/* Calculo de la suma */
for (i=0; i<TALLA; i++)
for (j=0; j<TALLA; j++)
s[i][j] = a[i][j] + b[i][j]

/* Calculo del producto */


for (i=0; i<TALLA; i++)
for (j=0; j<TALLA; j++) {
p[i][j] = 0.0;
for (k=0; k<TALLA; k++)
p[i][j] += a[i][k] * b[k][j];
}

/* Impresión del resultado de la suma */


printf ("Suma\n");
for (i=0; i<TALLA; i++) {
for (j=0; j<TALLA; j++)
printf ("%8.3f", s[i][j]);
printf ("\n");
}

/* Impresión del resultado del producto */


printf ("Producto\n");
for (i=0; i<TALLA; i++) {
for (j=0; j<TALLA; j++)
printf ("%8.3f", p[i][j]);
printf ("\n");
}
return 0;
}
tablas multidimensionales.

Este tipo de tablas se caracteriza por tener tres o más dimensiones. Al igual
que vectores y matrices, todos los elementos almacenados en ellas son del
mismo tipo de datos. La declaración de una tabla multidimensional tiene la
forma siguiente:

Tipo_de_datos nombre_tabla [tamaño1]…[tamaño_n];

Donde:

---[tamaño1]…[tamaño_n] son expresiones enteras constantes.

Representación Gráfica de un arreglo multidimensional N x M x 3

Podemos declarar arreglos multidimensionales muy fácilmente:

int a[10][8][3];
En este ejemplo, a es un arreglo de 10 × 8 x 3 enteros

La inicialización de arreglos multidimensionales necesita tantos bucles


anidados como dimensiones tengan estos:

#include <stdio.h>
int main()
{
float b[3][2][4];
int i, j, k;

for (i=0; i<3; i++)


for (j=0; j<2; j++)
for (k=0; k<4; k++)
b[i][j][k] = 0.0;
return 0;
}

Ejemplo

El siguiente ejemplo muestra el empleo de una tabla multidimensional.


Concretamente, el programa utiliza una tabla de 3 dimensiones para almacenar
1000 números aleatorios. Para generar números aleatorios se usa la
función rand de la librera estándar stdlib.h. También se ha usado la
función getchar (stdio.h), que interrumpe el programa y espera a que el
usuario presione una tecla.

#include <stdio.h>
#include <stdlib.h>
#define DIM 10
int main()
{
int tabla_random [DIM][DIM][DIM], a, b, c;
for (a= 0; a< DIM; a++)
for (b= 0; b< DIM; b++)
for (c= 0; c< DIM; c++)
tabla_random[a][b][c] = rand();
/* Muestra series de DIM en DIM elementos. */
for (a= 0; a< DIM; a++)
for (b= 0; b < DIM; b++) {
for (c= 0; c < DIM; c++) {
printf("\n tabla[%d][%d][%d] = ", a, b, c );
printf("%d", tabla random[a][b][c] );
}
printf("\nPulse ENTER para seguir" );
getchar();
}
return 0;
}

Operaciones Básicas con Arreglos:

Recordando un poco, en la defición de arreglos dimos esta serie de ejemplos:

int var1[10];
char nombre[50];
float numeros[200];
long double cantidades[25];

Si tomamos el primer caso, estamos declarando un array de 10 variables


enteras, cada una de ellas quedará individualizada por el subíndice que sigue
al nombre del mismo es decir:

var1[0] , var1[1] , … , hasta var1[9] .

Nótese que la CANTIDAD de elementos es 10, pero su numeración va de 0 a


9 , y no de 1 a 10 . En resumen un array de N elementos tiene subíndices
válidos entre 0 y N - 1. Cualquier otro número usado como subíndice, traerá
datos de otras zonas de memoria, cuyo contenido es impredecible. Se puede
referenciar a cada elemento, en forma individual, tal como se ha hecho con las
variables anteriormente, por ejemplo:
var1[5] = 40 ;
contador = var1[3] + 7 ;
if(var1[0] >> = 37)
..................

También es posible utilizar como subíndice expresiones aritméticas, valores


enteros retornados por funciones, entre otros. Así podríamos escribir:

printf(" %d " , var1[ ++i] ) ;


var1[8] = var1[ i + j ] ;
...............................
int funcion(void) ;
var1[0] = var1[funcion() ] * 15 ;

Por supuesto los subíndices resultantes de las operaciones tienen que estar
acotados a aquellos para los que el array fue declarado y ser enteros.
Inicialización de Arreglos: La inicialización de los arrays sigue las mismas
reglas que vimos para los otros tipos de variables, es decir: Si se declaran
como globales (afuera del cuerpo de todas las funciones) cada uno de sus
elementos será automáticamente inicializado a cero. Si en cambio, su
declaración es local a una función, no se realiza ninguna inicialización,
quedando a cargo del programa cargar los valores de inicio. La inicialización
de un array local, puede realizarse en su declaración, dando una lista de
valores iníciales:

int numero[8] = { 4 , 7 , 0 , 0 , 0 , 9 , 8 , 7 } ;

Obsérvese que la lista está delimitada por llaves. Otra posibilidad, sólo válida
cuando se inicializan todos los elementos del array, es escribir:

int numero[] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , } ;

Donde se obvia la declaración de la cantidad de elementos, ya que está


implícita en la lista de valores constantes.

También se puede inicializar parcialmente un array, por ejemplo:


int numero[10] = { 1 , 1 , 1 } ;

En éste caso los tres primeros elementos del mismo valdrán 1, y los restantes
cero en el caso que la declaración sea global, ó cualquier valor impredecible
en el caso de que sea local.
Métodos de Ordenamiento

La importancia de mantener nuestros arreglos ordenados radica en que es


mucho más rápido tener acceso a un dato en un arreglo ordenado que en uno
desordenado.

Existen muchos algoritmos para la ordenación de elementos en arreglos,


enseguida veremos algunos de ellos.

a)Selección Directa

Este método consiste en seleccionar el elemento más pequeño de nuestra lista


para colocarlo al inicio y así excluirlo de la lista.

Para ahorrar espacio, siempre que vayamos a colocar un elemento en su


posición correcta lo intercambiaremos por aquel que la esté ocupando en ese
momento.

El algoritmo de selección directa es el siguiente:

i <- 1

mientras i<= N haz

min <-i

j <- i + 1

mientras j <= N haz

si arreglo[j] < [min] entonces

min <-j

j <- j + 1

intercambia(arreglo[min],arreglo[i])

i <- i +1
b)Ordenación por Burbuja

Es el método de ordenación más utilizado por su fácil comprensión y


programación, pero es importante señalar que es el más ineficiente de todos
los métodos .

Este método consiste en llevar los elementos menores a la izquierda del


arreglo ó los mayores a la derecha del mismo. La idea básica del algoritmo es
comparar pares de elementos adyacentes e intercambiarlos entre sí hasta que
todos se encuentren ordenados.

i <- 1

mientras i < N haz

j <- N

mientras j > i haz

si arreglo[j] < arreglo[j-1] entonces

intercambia(arreglo[j],arreglo[j-1])

j<j-1

i <- i +1

c)Ordenación por Mezcla

Este algoritmo consiste en partir el arreglo por la mitad, ordenar la mitad


izquierda, ordenar la mitad derecha y mezclar las dos mitades ordenadas en un
array ordenado. Este último paso consiste en ir comparando pares sucesivos de
elementos (uno de cada mitad) y poniendo el valor más pequeño en el
siguiente hueco.

procedimiento mezclar(dat,izqp,izqu,derp,deru)

inicio

izqa <- izqp

dera <- derp


ind <- izqp

mientras (izqa <= izqu) y (dera <= deru) haz

si arreglo[izqa] < dat[dera] entonces

temporal[ind] <- arreglo[izqa]

izqa <- izqa + 1

en caso contrario

temporal[ind] <- arreglo[dera]

dera <- dera + 1

ind <- ind +1

mientras izqa <= izqu haz

temporal[ind] <- arreglo[izqa]

izqa <- izqa + 1

ind <- ind +1

mientras dera <= deru haz

temporal[ind] <=dat[dera]

dera <- dera + 1

ind <- ind + 1

para ind <- izqp hasta deru haz

arreglo[ind] <- temporal[ind]


METODOS DE BUSQUEDA

Una búsqueda es el proceso mediante el cual podemos localizar un elemento


con un valor especifico dentro de un conjunto de datos. Terminamos con éxito
la búsqueda cuando el elemento es encontrado.

A continuación veremos algunos de los algoritmos de búsqueda que existen.

a)Búsqueda Secuencial

A este método tambien se le conoce como búsqueda lineal y consiste en


empezar al inicio del conjunto de elementos , e ir atravez de ellos hasta
encontrar el elemento indicado ó hasta llegar al final de arreglo.

Este es el método de búsqueda más lento, pero si nuestro arreglo se encuentra


completamente desordenado es el único que nos podrá ayudar a encontrar el
dato que buscamos.

ind <- 1

encontrado <- falso

mientras no encontrado y ind < N haz

si arreglo[ind] = valor_buscado entonces

encontrado <- verdadero

en caso contrario

ind <- ind +1

b)Búsqueda Binaria

Las condiciones que debe cumplir el arreglo para poder usar búsqueda binaria
son que el arreglo este ordenado y que se conozca el numero de elementos.

Este método consiste en lo siguiente: comparar el elemento buscado con el


elemento situado en la mitad del arreglo, si tenemos suerte y los dos valores
coinciden, en ese momento la búsqueda termina. Pero como existe un alto
porcentaje de que esto no ocurra, repetiremos los pasos anteriores en la mitad
inferior del arreglo si el elemento que buscamos resulto menor que el de la
mitad del arreglo, o en la mitad superior si el elemento buscado fue mayor.

La búsqueda termina cuando encontramos el elemento o cuando el tamaño del


arreglo a examinar sea cero.

encontrado <- falso

primero <- 1

ultimo <- N

mientras primero <= ultimo y no encontrado haz

mitad <- (primero + ultimo)/2

si arreglo[mitad] = valor_buscado entonces

encntrado <- verdadero

en caso contrario

si arreglo[mitad] > valor_buscado entonces

ultimo <- mitad - 1

en caso contrario

primero <- mitad + 1

c)Búsqueda por Hash

La idea principal de este método consiste en aplicar una función que traduce el
valor del elemento buscado en un rango de direcciones relativas. Una
desventaja importante de este método es que puede ocasionar colisiones.

funcion hash (valor_buscado)

inicio

hash <- valor_buscado mod numero_primo


fin

inicio <- hash (valor)

il <- inicio

encontrado <- falso

repite

si arreglo[il] = valor entonces

encontrado <- verdadero

en caso contrario

il <- (il +1) mod N

hasta encontrado o il = inicio

También podría gustarte