jueves, 17 de marzo de 2011

Capitulo 5. Arreglos

Fuente:
Programación en C++ / Principios y Aplicaciones (resumen)
Carlos Romero Shollande

 1. Introducción 

Un arreglo es una estructura homogénea compuesta por varios datos del mismo tipo que comparten un nombre común, a los que se puede acceder por la posición que ocupa cada uno de ellos, dentro del arreglo.
Cada elemento puede ser accedido directamente por el nombre de la variable arreglo acompañado por uno o más subíndices encerrados entre corchetes
Un arreglo puede tener una o varias dimensiones. 

2. Arreglos Unidimensionales

Sintaxis      :    tipo nombre_arreglo[tamaño];
Propósito   :    Declarar el tipo base de cada uno de los elementos de un arreglo que tiene una sola dimensión y asignar el tamaño máximo de elementos, el mismo que es colocado entre corchetes. También se le conoce como vector o lista.
Ejemplo     :     int x[10];

En el ejemplo, int declara que el tipo base de cada uno de los elementos del vector “x” es entero y [10] define que dicho vector guardará 10 elementos.

Gráfica 1. Vector de diez elementos.













Observar el siguiente fragmento de programa:

main()  {
            int j, x[30];
            for(j=0;j<80;j++) x[j]=1;   }

Este bucle iterará 80 veces incluso aunque “x” tenga 30 elementos. Esto hace superar los límites establecidos, ocasionando un desbordamiento en el programa.
No intentar este ejemplo, puede dañar el sistema.
Si dos arreglos usan el mismo subíndice para referirse a términos homólogos se llaman arreglos paralelos.
Estos arreglos se pueden procesar simultáneamente. Ejemplo, cuando un primer vector define los nombres de cada alumno y un segundo vector sus respectivas notas.

Ejemplo:
Ingresar el orden y cada uno de los elementos de un vector. Calcular y reportar la suma acumulativa de dichos elementos.

Análisis:
Para leer los elementos del arreglo X[i], se requiere conocer cuantos datos se van a leer (n) y luego hacer un bucle para leer cada uno de ellos haciendo variar el subíndice (i) desde 1 hasta n.
Para calcular la suma acumulativa requerida se aplica el mismo procedimiento del cálculo de la suma de los números naturales (capítulo 4), pero considerando como sumandos a los valores de los elementos del vector. Una vez calculada la suma acumulativa sólo nos queda imprimir su último valor (S).

Codificación:
#include <iostream.h>     // Suma Acumulativa de elementos de vector
#include <conio.h>
main()    {
int S;                                // Suma acumulativa
int i;                                 // Subíndice del vector
int n;                                // Número de elementos del vector
int X[10];                         // Elementos del vector
clrscr();
cout<<“Número de elementos:  “;
cin>>n; cout<<“\n\n”;
for(i=1;i<=n;i++)    {                              // Ingreso de los datos del arreglo
cout <<“Elemento de la posición”<<i<<” : ”;cin>>X[i];
}
S=0;                                                     // Valor inicial de la suma acumulativa
for(i=1;i<=n;i++)  S=S+X[i];                   // Acumulación de un elemento en la suma
cout<<”\n\nSuma acumulativa :  “<<S;
getch();
}

3. Arreglos Bidimensionales

Sintaxis      :    tipo nombre_arreglo[tamañoF][tamañoC];
Propósito   :    Declarar el tipo base de cada uno de los elementos de un arreglo que tiene dos dimensiones (filas y columnas) y asignar el tamaño máximo de las filas y las columnas, cada uno de los cuales está colocado entre corchetes. También se llama matriz o tabla.
Ejemplo     :    int A[3][4];

Este ejemplo declara al arreglo bidimensional “A”, cuyos elementos son de tipo entero de tamaño 3 x 4 (3 filas y 4 columnas). Cada tamaño debe ir entre sus propios corchetes.

Gráfica 2. Matriz con tres filas y cuatro columnas

Los arreglos bidimensionales definen la ubicación de cada uno de sus elementos por medio de dos subíndices, donde el primer índice indica la fila y el segundo la columna.
Cuando se accede a un arreglo el índice más a la derecha cambia más rápido que el que esta más a la izquierda.
Existen diversos tipos de arreglos bidimensionales o matrices, los que se pueden definir de la siguiente manera:

3.1. MATRIZ CERO

La matriz cero tiene asignado el valor cero en todos sus elementos. Por ejemplo:






3.2. MATRIZ UNIDAD

La matriz unidad tiene asignado el valor uno en todos sus elementos. Por ejemplo: 





3.3. MATRIZ CUADRADA

Es la matriz en la cual el número de filas es igual al número de columnas. Este tipo de matriz presenta dos diagonales:

  • La diagonal principal (inclinada hacia la izquierda)
  • La diagonal secundaria (inclinada hacia la derecha)











3.4. MATRIZ IDENTIDAD

Es una matriz cuadrada con el valor uno en cada elemento de su diagonal principal, y cero en todos los demás elementos. Por ejemplo:






3.5. MATRIZ DIAGONAL

Es una matriz cuadrada en la cual los elementos que se encuentran sobre la diagonal principal pueden tener cualquier valor y el resto de valores son ceros. Por ejemplo:







3.6. MATRIZ TRIANGULAR

Es una matriz cuadrada cuyos valores diferentes de cero caen todos sobre la diagonal principal y a un lado de dicha diagonal.
Si todos los elementos caen sobre y a la derecha de la diagonal principal se llama “matriz triangular superior”.







Si todos los elementos caen por debajo y a la izquierda de la diagonal principal se llama “matriz triangular inferior”.






3.7. MATRIZ ESTRICTAMENTE TRIANGULAR

Es una matriz cuadrada que contiene elementos diferentes de cero solamente a un lado de la diagonal principal y ceros sobre dicha diagonal.
Si dichos elementos caen sobre y a la derecha de la diagonal principal se llama “matriz estrictamente triangular superior”.







Si dichos elementos caen por debajo y a la izquierda de la diagonal principal se llama “matriz estrictamente triangular inferior”.







3.8. MATRIZ TRANSPUESTA

La matriz transpuesta viene a ser igual a la matriz original pero en donde las filas se transponen en columnas y las columnas en filas.
Por tanto, si A es una matriz de orden m x n, entonces su transpuesta B será una matriz de orden n x m, cuyos elementos se determinan como:   B[i][j] = A[j][i]
Ejemplo:






Ejemplo:

Ingresar el orden de una matriz y cada uno de sus elementos. Si la matriz es cuadrada calcular la suma del vector diagonal principal. En caso contrario, formar un vector fila con los mayores elementos de las columnas pares y los menores elementos de las columnas impares.

Codificación:
#include <iostream.h>    // SUMA DIAGONAL PRINCIPAL – VECTOR FILA
#include <conio.h>
main()    {
int m, n;                   // Tamaño de la matriz
int i, j;                      // Subíndices de las filas y las columnas de la matriz
int x[20][20];           // Elementos de la matriz
int s;                        // Suma de los elementos del vector diagonal principal
int u[20];                 // Vector fila que incluye a menores y mayores elementos de cada columna
clrscr();
gotoxy(20,6); cout<<“Número filas:”;
gotoxy(42,6); cin>>m;
gotoxy(20,8); cout<<”Número columnas: ”;
gotoxy(42,8); cin>>n;
clrscr();
gotoxy(25,2); cout<<”ELEMENTOS DE LA MATRIZ”;
for(i=1; i<m; i++)     {
for(j=1; j<=n; j++)     {
gotoxy(10,5); cout<<”Elemento Fila ”<<i<<” Columna ”<<j<<” : ”;
gotoxy(40,5);cin>>x[i][j];    }
}
clrscr();
cout<<”MATRIZ ORIGINAL\n\n”;
for(i=1; i<=m; i++)      {
for(j=1; j<=n; j++) cout<<x[i][j]<<”    “;
cout<<”\n”;    }
if(m==n)      {
s=0;
for(i=1; i<=m; i++)   for(j=1; j<=m; j++)   if(i==j) s = s + x[i][j];
cout<<”\nSuma de la diagonal principal: “<<s;
}
else     {
cout<<”\nVector Mayor – Menor  \n\n”;
for(j=1; j<=n; j++)     {
if(j%2===0)    {
u[j]=x[1][j];
for(i=2; i<=m; i++) if(x[i][j]>u[j]) u[j]=x[i][j];
}
else     {
u[j]=x[1][j];
for(i=2; i<=m; i++) if(x[i][j]<u[j]) u[j]=x[i][j];
}
}
for(j=1; j<=n; j++) cout<<u[j]<<”    “;
}
getch();
}

4. Arreglos Multidimensionales

Sintaxis      :    tipo nombre_arreglo[tam1][tam2]...[tamN];
Propósito   :    Declarar el tipo base de cada elemento de un arreglo que tiene N dimensiones y asignar el tamaño máximo a cada dimensión. También se le conoce como poliedro.
Ejemplo     :    int x[5][10][4];

Esta sentencia crea un arreglo entero de 5x10x4 elementos.
Los enteros requieren de 2 bytes; entonces la cantidad de memoria a utilizar será: 5 x 10 x 4 x 2 = 400 bytes
Si el arreglo fuera de tipo double (8 bytes de largo), entonces requerirá 1600 bytes.
Un programa con arreglos de más de 3 dimensiones puede encontrarse fuera de la memoria rápidamente.

5. Inicialización de Arreglos

Sintaxis      :    tipo nom_arreg[tm1][tm2]...[tmN]={list_val};
Propósito   :    Inicializar arreglos en forma global.
Ejemplo     :     int b[6]={1,2,3,4,5,6};

list_val es una lista de constantes separadas con comas, éstas son de tipo compatible con el tipo base del arreglo.
Esta sentencia pondrá la primera constante en la primera posición del arreglo, la segunda en la segunda posición, y así sucesivamente.
Después del final del bloque } debe ir punto y coma.
El  ejemplo anterior inicializa un arreglo de seis elementos enteros con los números del 1 al 6 e indica que b[0] tendrá el valor 1 y b[5] el 6.
Se puede dejar al C++ que dimensione automáticamente los arreglos, usando arreglos sin tamaño, esto se logra no especificando el tamaño de los mismos.
Entonces C++ creará automáticamente un arreglo lo suficientemente grande para guardar todos los inicializadores presentados.
Ejemplo:

int g[ ] = { 23,31,37,42,48,57,63 };

En el caso de arreglos unidimensionales el C++ no restringe las inicializaciones de arreglos sin tamaño.
Para arreglos multidimensionales, se deben especificar todas las dimensiones excepto la de más a la izquierda para permitir indexar el arreglo apropiadamente.
En este sentido se pueden construir tablas de longitud variable mientras el compilador asigna automáticamente el almacenamiento suficiente. Por ejemplo:

int x[ ][2]?{     1,1,
            2,4,
            3,9,
            4,16     };

La ventaja de esta declaración relacionada con el tamaño, es que se puede alargar o acortar la tabla sin cambiar las dimensiones del arreglo.

6. Uso de Macros

Sintaxis       :     #define nombre_macro valor_macro
Propósito    :     Sustituir el nombre de la macro por el correspondiente valor de la macro.
Ejemplo      :     #include <iostream.h>
                        #define MAXIMO 18
                        int x[MAXIMO];
                        main()  {
                                   int i;
                                   for(i=1;i<=MAXIMO;i++) cin >>x[i]);
                                   for(i=1;i<=MAXIMO;i++) cout <<x[i];  }

Aquí la macro MAXIMO se usa para dar una dimensión 18 al arreglo de enteros x. Observar que no hay punto y coma detrás de la segunda sentencia.
La sustitución es realizada por el C++ antes de iniciarse la traducción de las sentencias del programa fuente.
El resto del programa fuente puede utilizar una o varias veces el nombre de la macro en lugar de su valor.
Se puede incluir cualquier número de espacios entre el nombre de la macro y su valor, pero, una vez que comienza el valor, sólo puede terminarla una nueva línea.
La macro controla la condición del bucle for que inicializa el arreglo.
Si se tiene un arreglo que posee diversas subrutinas, para acceder al arreglo, en vez de la codificación estricta del arreglo con una constante, es mejor definir un tamaño y usar la macro siempre que se necesite dicho tamaño.
El valor de una macro puede ser también una cadena de caracteres limitada por un par de comillas, por ejemplo:

#define ERROR “Error de sintaxis”
…….
cout<<ERROR;

Este código provoca que el compilador sustituya la cadena “Error de sintaxis” cuando encuentre  la macro ERROR.
Las macros también se utilizan para dar otros nombres a identificadores y símbolos. Ejemplo:

#define entero int
#define inicio {
#define fin }
#define programa main
#define imprimir cout
programa()
            inicio
                        entero n=5;
                        imprimir<<n;
            fin

Ejemplo:

El número de productos del tipo i(=1,2,…,M) vendidos por el vendedor j(=1,2,…,N) en el mes k(=1, 2,… 12), en una empresa fabricante de calzado está designada por VENTAS (i, j, k). Reportar: (a) ventas anuales de cada vendedor por cada tipo de producto, ventas de la empresa al año por cada tipo de producto, (c) ventas totales anuales de cada vendedor y ventas totales al año de la empresa.

Codificación:
#include <iostream.h>    // Ventas anuales de empresa
#include <conio.h>
#define LIM 10
main()     {
int m;                                      // Número de tipos de productos
int n;                                       // Número de vendedores
int i;                                        // Subíndice de los tipos de productos
int j;                                        // Subíndice de los vendedores
int k;                                       // Subíndice de los meses
int ventas[LIM][LIM][LIM];    // Poliedro de ventas
int s;                                       // Ventas totales al año
int y[LIM] [LIM];                   // Matriz de ventas del mes por producto
int z[LIM] [LIM];                   // Matriz de ventas del vendedor por producto
int q[LIM];                             // Vector ventas anuales por producto
int t[LIM];                              // Vector ventas anuales por vendedor
int r[LIM];                              // Vector ventas totales del mes
clrscr();
do    {
cout<<”\nNúmero de vendedores :”;cin>>n;    }
while(n<=0);
do    {
cout<<”\nNúmero de tipos de productos : “;cin>>m;   }
while(m<=0);
clrscr();
for(i=1;i<=m;i++)      {
for(j=1;j<=n;j++)      {
for(k=1;k<=12;k++)     {
cout<<”Ventas de producto “<<i<<” por vendedor ”<<j<<” en mes ”<<k<<”: ”;
cin>>ventas[i][j][k];   }
}
}
getch();  clrscr();
cout<<”Ventas anuales de cada vendedor por cada tipo de producto\n\n”;
for(i=1;i<=m;i++)      {
for(j=1;j<=n;j++)     {
z[i][j]=0;
for(k=1;k<=12;k++)     {
z[i][j] = z[i][j] + ventas[i][j][k];    }
}
}
cout<<”Vendedor/Producto  “;
for(i=1;i<=m;i++) cout<<i<<”     “;  cout<<”\n”;
for(j=1;j<=n;j++)     {
gotoxy(2,3+j);cout<<j;
for(i=1;i<=m;i++)     {
gotoxy(14+6*i,3+j);cout<<z[i][j];    }
}
getch();  clrscr();
cout<<”Ventas de la empresa al año por cada tipo de producto\n\n”;
for(i=1;i<=m;i++)     {
q[i]=0;
for(j=1;j<=n;j++)     {
for(k=1;k<=12;k++)     {
q[i] = q[i] + ventas[i][j][k];    }
}
}
cout<<”Producto  Ventas";
for(i=1;i<=m;i++)     {
gotoxy(2,4+i);cout<<i;
gotoxy(12,4+i);cout<<q[i];   }
getch(); clrscr();
cout<<”Ventas totales anuales de cada vendedor\n\n”;
for(j=1;j<=n;j++)    {
t[j]=0;
for(i=1;i<=m;i++)    {
for(k=1;k<=12;k++)    {
t[j] = t[j] + ventas[i][j][k];   }
}
}
cout<<”Vendedor     Ventas";
for(j=1;j<=n ;j++)      {
gotoxy(2,4+j);cout<<j;
gotoxy(13,4+j);cout<<t[j];
}
getch(); clrscr();
s=0;
for(i=1;i<=m;i++)     {
for(j=1;j<=n;j++)     {
for(k=1;k<=12;k++) s = s + ventas[i][j][k];    }
}
gotoxy(5,6);cout<<Venta total de la empresa : ”<<s<<”\n”;
getch();
}

7. Operaciones con Arreglos

7.1. Suma de Arreglos

La suma vectorial es factible realizarla sólo cuando los tamaños de los vectores sean iguales.
Consiste en sumar los elementos ubicados en la misma posición en ambos vectores y el resultado se ubica en la misma posición del vector suma:

z[4] = x[4] + y[4]

La suma matricial es factible cuando el número de filas de ambas matrices sean iguales y el número de columnas también sean iguales.
Consiste en sumar los elementos ubicados en la misma posición en ambas matrices (X e Y) y el resultado se ubica en la misma posición en la matriz suma (Z):

Z[3][2] = X[3][2] + Y[3][2]

7.2. Resta de Arreglos

Tanto la diferencia vectorial como la diferencia matricial es similar a la suma vectorial o suma matricial respectivamente, excepto que el signo de suma se reemplaza por un signo menos.
Esta operación también será factible cuando ambos arreglos tienen el mismo orden.
Ejemplo para la diferencia vectorial:

z[3] = x[3] - y[3]

Ejemplo para la diferencia matricial:

Z[2][4] = X[2][4] - Y[2][4]

7.3. Multiplicación Escalar con Arreglos

En la multiplicación escalar todos los elementos de una matriz se multiplican por una constante dada.
Por ejemplo, una matriz de orden 2 x 3 multiplicada por la constante 12:

Y[1][1] = 12 * X[1][1]
Y[1][2] = 12 * X[1][2]
…….
Y[2][3] = 12 * X[2][3]

7.4. Multiplicación Vectorial con Arreglos

Para que sea factible la multiplicación vectorial, el primer vector debe ser un vector fila y el segundo un vector columna, ambos del mismo orden.
El resultado es un solo elemento obtenido mediante una suma acumulativa de los productos de los elementos ubicados en el primer vector por los correspondientes elementos ubicados en el segundo vector.
Por ejemplo, el producto de los vectores x e y, ambos de orden 5:

P = x[1]*y[1] + x[2]*y[2] +  ….  + x[5]*y[5]

7.5. Multiplicación Matricial con Arreglos

Para que sea factible el cálculo de la matriz producto, se requiere que el número de columnas de la primera matriz sea igual al número de filas de la segunda matriz.
La matriz producto resultante tendrá un número de filas igual al de la primera matriz y un número de columnas igual al de la segunda matriz.
Cada uno de los elementos de la matriz producto es una suma acumulativa de los productos de los elementos ubicados en la fila de la primera matriz por los correspondientes elementos ubicados en la columna de la segunda matriz. Ejemplo:

z[2][3] =          x[2][1] * y[1][3] + x[2][2] * y[2][3] + ... + x[2][k] * y[k][3] + ... + x[2][N] * y[N][3]

Ejemplo:

Ingresar el orden de dos matrices, las mismas que poseen números extraídos al azar y comprendidos entre 0 y 20. Si es factible, calcular y reportar la matriz producto. En caso contrario, reportar el mensaje. “No es factible el producto de matrices”.

Análisis:
Los números al azar se obtienen usando las funciones rand() y randomize() estudiados en el párrafo 10.4 del capitulo 1 y la matriz producto se obtiene usando los conceptos del párrafo 7.4 del presente capitulo.

Codificación:
#include <iostream.h>       // Matriz producto
#include <conio.h>
#include <stdlib.h
main()    {
int q, r;                               // Tamaño de la primera matriz
int s, t;                                // Tamaño de la segunda matriz
int h, i;                                // Subíndices de filas y columnas de primera matriz
int j, k;                                // Subíndices de filas y columnas de segunda matriz
int x[20][20];                      // Elementos de la primera matriz
int y[20][20];                      // Elementos de la segunda matriz
int z[20][20];                      // Elementos de la matriz producto
clrscr();
gotoxy(10,6); cout<<“Número filas primera matriz: ”;
gotoxy(45,6); cin>>q;
gotoxy(10,8); cout<<”Número columnas primera matriz: ”;
gotoxy(45,8); cin>>r;
gotoxy(10,10); cout<<“Número filas segunda matriz: ”;
gotoxy(45,10); cin>>s;
gotoxy(10,12); cout<<”Número columnas segunda matriz: ”;
gotoxy(45,12); cin>>t;
randomixe();
for(h=1;h<=q;h++)  for(i=1;i<=r;i++) x[h][i] = rand()%21;
for(j=1;j<=s;j++)  for(k=1;k<=t;k++) y[j][k] = rand()%21;
if(r==s)                  {
clrscr();
for(h=1;h<=q;h++)     {
for (k=1;k<=t;k++)     {
z[h][k]=0;                            // Valor inicial de suma acumulativa
for(i=1;i<=r,i++) z[h][k] = z[h][k] + x[h][i]* y[i][k];    }
}
cout<<”           PRIMERA MATRIZ\n\n”;
for(h=1;h<=q;h++)      {
for(i=1;i<=r;i++)       {
gotoxy(5*i,h+3); cout<<x[h][i];    }
cout<<”\n”;
}
gotoxy(10,18);cout<<”Para continuar presione cualquier tecla”;
getch();   clrscr();
cout<<”           SEGUNDA MATRIZ\n\n”;
for(j=1;j<=s;j++)     {
for(k=1;k<=t;k++)     {
gotoxy(5*k,j+3);cout<<y[j][k];           }
cout<<”\n”;
}
gotoxy(10,18);cout<<”Para continuar presione cualquier tecla”;
getch();   clrscr();
cout<<”           MATRIZ PRODUCTO\n\n”;
for(h=1;h<=q;h++)     {
for(k=1;k<=t;k++)      {
gotoxy(5*k,h+3);cout<<z[h][k];     }
cout<<”\n”;    }
}
else     {
clrscr();
cout<<”El producto de matrices no es factible\n\n”;      }
getch();
}