c4vectores2005 2006 versionmia - decsai.ugr.esdecsai.ugr.es/~lozano/mp1-0809/vectores.pdftema 4....

Post on 01-Sep-2019

9 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ÍNDICE GENERAL 1

Índice general4.1. Vectores . . . . . . . . . . . . . . . . . . . . . . . . . 2

4.1.1. Motivación . . . . . . . . . . . . . . . . . . . . 2

4.1.2. Declaración y Representación en Memoria . 5

4.1.3. Operaciones con Vectores . . . . . . . . . . 6

4.1.4. Modularización y Vectores . . . . . . . . . . 16

4.1.5. Algoritmos de Búsqueda . . . . . . . . . . . 30

4.1.6. Construcción de vectores en una función . 39

4.1.7. Trabajando con vectores locales . . . . . . . 44

4.1.8. Algoritmos de Ordenación . . . . . . . . . . 48

4.1.9. Cadenas de caracteres (cstring) . . . . . . . 73

4.2. Matrices . . . . . . . . . . . . . . . . . . . . . . . . . 83

4.2.1. Introducción . . . . . . . . . . . . . . . . . . . 83

4.2.2. Operaciones con matrices . . . . . . . . . . 86

4.2.3. Gestión de componentes útiles con matrices 88

4.2.4. Matrices de varias dimensiones . . . . . . . 92

4.2.5. Modularización con Matrices . . . . . . . . . 93

4.2.6. Gestión de filas de una matriz como vectores 99

Tema 4. Vectores y Matrices 2

TEMA 4. VECTORES Y MATRICES

4.1. VECTORES

4.1.1. MOTIVACIÓN

En casi todos los problemas, es necesario mantener una rela-ción entre variables diferentes o almacenar y referenciar varia-bles como un grupo. Para ello, los lenguajes ofrecen tipos máscomplejos que los vistos hasta ahora.

Un tipo de dato compuesto es una composición de tipos dedatos simples (o incluso compuestos) caracterizado por la or-ganización de sus datos y por las operaciones que se definensobre él.

Un vector es un tipo de dato, compuesto de un número fijo decomponentes del mismo tipo y donde cada una de ellas es di-rectamente accesible mediante un índice.

Tema 4. Vectores y Matrices 3

Ejemplo:

#include <iostream>

using namespace std;

int main(){

int cuantos;

double nota1, nota2, nota3, media;

cout << "Introduce nota 1: ";

cin >> nota1;

cout << "Introduce nota 2: ";

cin >> nota2;

cout << "Introduce nota 3: ";

cin >> nota3;

media = (nota1+nota2+nota3)/3.0;

cuantos=0;

if (nota1 > media)

cuantos++;

if (nota2 > media)

cuantos++;

if (nota3 > media)

cuantos++;

cout << "Media Aritmetica = " << media << endl;

cout << cuantos << " alumnos han superado la media\n";

return 0;

}

Tema 4. Vectores y Matrices 4

Problema: ¿Qué sucede si queremos almacenar las notas de50 alumnos?

Número de variables imposible de sostener y recordar

Solución: Introducir un tipo de dato nuevo que permita repre-sentar dichas variables en una única estructura de datos, reco-nocible bajo un nombre único.

notas[0] notas[1] notas[2]

notas= 2.4 4.9 6.7

Tema 4. Vectores y Matrices 5

4.1.2. DECLARACIÓN Y REPRESENTACIÓN EN MEMO-RIA

<tipo> <identificador>[<N.Componentes>];

<tipo> indica el tipo de dato común a todas las compo-nentes del vector.

<N.Componentes> determina el número de componentes delvector. El número de componentes debe conocerse a prioriy no es posible alterarlo durante la ejecución del programa.Pueden usarse literales ó constantes enteras (char, int, ...),pero nunca una variable

Las posiciones ocupadas por el vector están contiguas enmemoria.

double notas[3];

notas = ? ? ?

Consejo: Fomentad el uso de constantes para especificarel tamaño de los vectores.

int main(){

const int TOTAL_ALUMNOS = 100;

double notas[TOTAL_ALUMNOS];

}

Tema 4. Vectores y Matrices 6

Otros ejemplos:

int main(){

const int NUM_REACTORES=20;

int longitud=50;

int TemperaturasReactores[NUM_REACTORES]; // Correcto.

bool casados[40]; // Correcto.

char DNI[8]; // Correcto.

bool vector[longitud]; // Error en compilación.

..............

}

4.1.3. OPERACIONES CON VECTORES

4.1.3.1. ACCESO

Dada la declaración:<tipo> <identificador>[<N.Componentes>];

Cada componente se accede de la forma:

<Identificador de vector> [ <índice> ]

0 ≤ índice < N.Componentes

El índice de la primera componente del vector es 0.El índice de la última componente es <N.Componentes>-1.

Tema 4. Vectores y Matrices 7

double notas[3];

notas

notas[0] notas[1] notas[2]

? ? ?

? ? ?

notas[9] y notas[’3’] no son componentes correctas.

Cada componente es una variable más del programa, deltipo indicado en la declaración del vector. Por ejemplo, sideclaramos

double vector[3];

entonces vector[2] y vector[0] son variables de tipo double

Por lo tanto, con dichas componentes podremos realizartodas las operaciones disponibles (asignación, lectura concin, pasarla como parámetros actuales, etc)

Tema 4. Vectores y Matrices 8

4.1.3.2. ASIGNACIÓN

<Ident. vector> [ < índice> ] = <Expresión>;

<Expresión> ha de ser del mismo tipo que el definido enla declaración del vector (o al menos compatible).

No se permiten asignaciones globales sobre todos los ele-mentos del vector. Las asignaciones se deben realizar com-ponente a componente.

int main(){

double notas[3];

notas[0] = 5;

notas

notas[0] notas[1] notas[2]

? ? ?

5 ? ?

Tema 4. Vectores y Matrices 9

4.1.3.3. LECTURA Y ESCRITURA

La lectura y escritura se realiza componente a componente.

Para leer con cin o escribir con cout todas las componentesutilizaremos un bucle, como por ejemplo:

#include <iostream>

using namespace std;

int main(){

const int NUM_NOTAS = 10;

double notas[NUM_NOTAS], media;

for (int i=0; i<NUM_NOTAS; i++){

cout << "Introducir nota del alumno " << i << ": ";

cin >> notas[i];

}

media = 0;

for (int i=0; i<NUM_NOTAS; i++){

media = media + notas[i];

}

media = media / NUM_NOTAS;

cout << "\nMedia = " << media;

}

Tema 4. Vectores y Matrices 10

int main(){

const int DIM_VECTOR = 10;

double vector[DIM_VECTOR], dato;

dato = vector[0]; // Error logico ¿vector[0]?

for (int i=0 ; i<DIM_VECTOR ; i++)

vector[i] = 2*i; // <- double = int

dato = vector[0]; // Correcto

vector[15]=7; // Posible error grave en ejecucion!

.........................

return 0;

}

Muy importante: El compilador no comprueba el acceso a lascomponentes, por lo que cualquier modificación de una com-ponente inexistente tiene consecuencias imprevisibles.

Tema 4. Vectores y Matrices 11

4.1.3.4. INICIALIZACIÓN

C++ permite inicializar una variable de tipo vector, en la decla-ración.

int vector[3]={4,5,6};

inicializa vector[0]=4 vector[1]=5 vector[2]=6

int vector[7]={3,5};

inicializa vector[0]=3 vector[1]=5 y el resto se inicializana cero.

int vector[7]={0};

inicializa todas las componentes a cero.

int vector[]={1,3,9};

automáticamente el compilador asume int vector[3]

4.1.3.5. TRABAJANDO CON EL VECTOR

No es necesario utilizar todas las componentes del vector. Loshuecos suelen dejarse en la zona de índices altos.

Por eso, el programador debe usar una variable entera, utilque indique el número de componentes usadas. Como conven-ción, usaremos identificadores del tipo utilNombreDelVector outil_nombreDelVector

Tema 4. Vectores y Matrices 12

#include <iostream>

using namespace std;

int main(){

const int DIM_NOTAS = 100;

int util_notas;

double notas[DIM_NOTAS], media;

do{

cout << "Introduzca el n\’umero de alumnos (entre 1 y "

<< DIM_NOTAS << "): ";

cin >> util_notas;

}while (util_notas<1 || util_notas>DIM_NOTAS);

for (int i=0; i<util_notas; i++){

cout << "nota[" << i << "] --> ";

cin >> notas[i];

}

media=0;

for (int i=0; i<util_notas; i++){

media=media+notas[i];

}

cout << "\nMedia: " << media/util_notas << endl;

return 0;

}

Tema 4. Vectores y Matrices 13

Ejemplo: Buscar un elemento en un vector.

Recorre las componentes vector[i] del vector

mientras no se terminen Y

mientras no se encuentre el elemento

Si vector[i] == elemento,

recuerda la posición y sal del bucle

si no

i++

#include <iostream>

using namespace std;

int main(){

const int DIM_VECTOR = 100;

double vector[DIM_VECTOR], buscado;

int i, util_vector;

bool encontrado;

util_vector=50;

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

vector[i] = i*i;

cout << "\n\nIntroduzca valor a buscar";

cin >> buscado;

Tema 4. Vectores y Matrices 14

encontrado=false;

i=0;

while ((i<util_vector) && !encontrado)

if (vector[i] == buscado)

encontrado=true;

else

i++;

if (encontrado)

cout << "\nEncontrado en la posición "<< i;

else

cout << "\nNo encontrado";

}

encontrado=false;

for (i=0; i<util_vector && !encontrado ; i++)

if (vector[i] == buscado)

encontrado=true;

if (encontrado)

cout << "\nEncontrado en la posición " << i-1 ; // <-

else

cout << "\nNo encontrado" << endl;

}

Tema 4. Vectores y Matrices 15

encontrado=false;

for (i=0; i<util_vector && !encontrado ; i++)

if (vector[i] == buscado){

posicion = i;

encontrado = true;

}

if (encontrado)

cout << "\nEncontrado en la posición " << posicion;

else

cout << "\nNo encontrado" << endl;

}

Ejercicio. Ver si un vector de caracteres es un palíndromo, esdecir, que se lee igual de izquierda a derecha que de derechaa izquierda. Por ejemplo, (’A’,’B’,’B’,’A’) sería un palíndro-mo.

Tema 4. Vectores y Matrices 16

4.1.4. MODULARIZACIÓN Y VECTORES

4.1.4.1. PASANDO INDIVIDUALMENTE UNA COMPONENTE COMO

PARÁMETRO

Las componentes son variables cualesquiera por lo que laspodemos pasar como parámetro a cualquier función.

Ejemplo. De un vector de char, imprimid la mayúscula corres-pondiente a la primera componente.

char palabra[10];

palabra[0]=’h’;

palabra[1]=’o’;

palabra[2]=’l’;

palabra[3]=’a’;

cout << toupper(palabra[0]);

Si queremos, podemos modificar la componente:

char palabra[10];

palabra[0]=’h’;

palabra[1]=’o’;

palabra[2]=’l’;

palabra[3]=’a’;

palabra[0] = toupper(palabra[0]);

Tema 4. Vectores y Matrices 17

Obviamente también funciona el paso por referencia.

Ejemplo. De un vector de int, incrementad en 1 el valor de to-das las componentes.

void Incrementa(int &dato){

dato = dato+1;

}

int main(){

int vector[10], int util_vector;

// Asignación de valores a las componentes

for(int i=0; i<util_vector; i++)

Incrementa(vector[i]);

}

Tema 4. Vectores y Matrices 18

4.1.4.2. PASANDO TODAS LAS COMPONENTES COMO PARÁME-TRO

¿Podemos pasar de golpe todas las componentes a una fun-ción?

No puede pasarse una copia de todo el vector (como unpaso por valor)

Pero sí se puede indicar a la función dónde empieza el vec-tor (parámetro actual), para que la función acceda a suscomponentes.

Para indicar la dirección dónde empieza el vector, se pone[] en el parámetro formal.

... (tipoBase vector[], ...)

En la llamada, se pasa como parámetro actual el identifica-dor de un vector con el mismo tipo base que el correspon-diente parámetro formal (sin poner los corchetes [])

Tema 4. Vectores y Matrices 19

#include <iostream>

using namespace std;

void ImprimeVector(double v[]){ // <- Con corchetes

for (int i=0; i<4; i++)

cout << v[i] << endl;

}

int main(){

double vector[4]={1,5,6,9};

ImprimeVector(vector); // <- Sin corchetes

}

Entorno de main

vector

Entorno de ImprimeVector

v

a a

1 5 6 9

Tema 4. Vectores y Matrices 20

IMPORTANTE: la función podrá modificar las componentes delvector pasado como parámetro actual

#include <iostream>

using namespace std;

void Pon_a_cero(double v[]){ // <- NO SE PONE &

for (int i=0; i<4; i++)

v[i] = 0;

}

int main(){

double vector[4]={1,5,6,9};

Pon_a_cero(vector);

}

Entorno de main

1

vector

Entorno de Pon_a_cero

v

5 6 9

a a

Tema 4. Vectores y Matrices 21

Las funciones ImprimeVector y Pon_a_cero sólo sirven para unvector de 4 componentes. Normalmente, pasaremos tambiéncomo parámetro a la función, el número de componentes utili-zadas (pero no la dimensión)

#include <iostream>

using namespace std;

void ImprimeVector (double v[], int util_v){

for (int i=0; i<util_v; i++)

cout << v[i] << endl;

}

int main(){

const int DIM_VECTOR = 5;

double vector[DIM_VECTOR]={4,2,7};

int util_vector=3;

ImprimeVector(vector, util_vector);

}

Entorno de main

3

4

vector

util_vector

Entorno de ImprimeVector

3 util_v

v

2 7 ? ?

a a

Tema 4. Vectores y Matrices 22

Ejercicio. Calculad la mayor componente de un vector de double.

Tema 4. Vectores y Matrices 23

Ejemplo. Cread un void llamado LecturaVectorDouble para leerdesde teclado los valores de un vector.

Primero, leyendo las componentes útiles dentro del void.

void LecturaVectorDouble (double v[], int &util_v){ // <- &

cout << "Introduzca número de componentes: ";

cin >> util_v;

cout << "\nIntroduzca valores reales:\n";

for (int i=0 ; i<util_v ; i++){

cout << "Posición " << i << ": ";

cin >> v[i];

}

}

int main(){

const int DIM_VECTOR = 5;

double vector[DIM_VECTOR]={4,2,7};

int util_vector;

LecturaVectorDouble(vector, util_vector);

.............

}

Tema 4. Vectores y Matrices 24

Segundo, leyendo dicho valor antes de llamar al void

void LecturaVectorDouble (double v[], int util_v){

cout << "\nIntroduzca valores reales:\n";

for (int i=0 ; i<util_v ; i++){

cout << "Posición " << i << ": ";

cin >> v[i];

}

}

int main(){

const int DIM_VECTOR = 5;

double vector[DIM_VECTOR]={4,2,7};

int util_vector;

cout << "Introduzca n\’umero de componentes: ";

cin >> util_vector;

LecturaVectorDouble(vector, util_vector);

.............

}

¿Cual es preferible?

Tema 4. Vectores y Matrices 25

En general, en una función cualquiera<tipo> funcion (TipoBase v[], ....)

indicamos al compilador que la función va a recibir por refe-rencia unas posiciones contiguas en memoria (las del vectorparámetro actual): cada una es de tipo de dato TipoBase. Deesta forma, cuando dentro del módulo accedamos a v[2], porejemplo, el compilador dará dos saltos tan grandes como digael TipoBase a partir de la primera posición del parámetro actual.

Entorno de main

3

4

vector

util_vector

Entorno de ImprimeVector

3 util_v

v

2 7 ? ?

a a

v [2]

Tema 4. Vectores y Matrices 26

Al tener acceso desde la función a las componentes del vec-tor pasado como parámetro actual, se pueden producir efectoscolaterales indeseados.

#include <iostream>

using namespace std;

void Imprime_doble_de_vector (double v[], int util_v){

int i;

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

v[i]=2*v[i];

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

cout << v[i] << endl;

}

int main(){

const int DIM_VECTOR = 5;

double vector[DIM_VECTOR]={4,2,7};

int util_vector=3;

Imprime_doble_de_vector(vector, util_vector); // -> 8, 4, 14

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

cout << vector[i] << endl; // -> 8, 4, 14 !!!!

}

Tema 4. Vectores y Matrices 27

Si se quiere pasar un vector a una función y que ésta no puedamodificarlo es necesario utilizar el calificador const.

#include <iostream>

using namespace std;

void Imprime_doble_de_vector (const double v[], int util_v){

int i;

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

v[i]=2*v[i]; // Error en compilación :-)

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

cout << v[i] << endl;

}

Representación en memoria: exactamente la misma.

Tema 4. Vectores y Matrices 28

El parámetro actual y el formal han de ser del mismo tipo dedato: Con vectores, esto significa que han de tener el mismotipo de dato base (aunque tengan distintas dimensiones)

void ImprimeVector (const double v[], int util_v){

for (int i=0; i<util_v; i++)

cout << v[i] << endl;

}

int main(){

const int DIM_VECTOR_GRANDE = 10;

const int DIM_VECTOR_PEQUE = 5;

double vector_grande[DIM_VECTOR_GRANDE];

double vector_peque[DIM_VECTOR_PEQUE];

<Asignación de valores a los vectores>

// Todas estas llamadas son correctas:

ImprimeVector (vector_grande , 4);

ImprimeVector (vector_grande , 5);

ImprimeVector (vector_peque , 4);

ImprimeVector (vector_peque , 5);

ImprimeVector (vector_peque , 9);// Imprime basura a partir

// de la sexta posicion

}

Tema 4. Vectores y Matrices 29

Sin embargo no podemos pasar como parámetros actuales,vectores de tipo de dato base compatible con el formal.

void ImprimeVector (const double v[], int util_v){

for (int i=0; i<util_v; i++)

cout << v[i] << endl;

}

int main(){

const int DIM_VECTOR_INT = 10;

const int DIM_VECTOR_DOUBLE = 10;

int vector_int[DIM_VECTOR_INT];

double vector_double[DIM_VECTOR_DOUBLE];

<Asignacion de valores a los vectores>

ImprimeVector(vector_int, 3); // Correcto. Tipos iguales

ImprimeVector(vector_double, 3); // Error de compilación

}

Solución. Definiremos un procedimiento por cada tipo de dato

void ImprimeVectorInt (const int v[], int util_v){

for (int i=0; i<util_v; i++)

cout << v[i] << endl;

}

void ImprimeVectorDouble (const double v[], int util_v){

for (int i=0; i<util_v; i++)

cout << v[i] << endl;

}

Nota. C++ permite el uso de sobrecargas para evitar este problema.

Tema 4. Vectores y Matrices 30

4.1.5. ALGORITMOS DE BÚSQUEDA

Al proceso de encontrar un elemento específico en un vectorse denomina búsqueda.

Búsqueda secuencial. Técnica más sencilla.

Búsqueda binaria. Técnica más eficiente, aunque requiereque el vector esté ordenado.

4.1.5.1. BÚSQUEDA SECUENCIAL

El vector no se supone ordenado.

Como no se modifica, se pasa como const <TipoBase> v[]

Devuelve la posición dónde se encuentra o un valor impo-sible de índice si no se encuentra (por ejemplo, -1)

Tema 4. Vectores y Matrices 31

#include <iostream>

using namespace std;

void LecturaVectorDouble (double v[], int util_v);

int BuscaSec(const double v[], int util_v, double buscado);

int main(){

const int DIM_VECTOR = 10;

double vector[DIM_VECTOR];

int util_vector = 5;

int posicion;

LecturaVectorDouble (vector, util_vector);

cin >> encontrar;

posicion = BuscaSec(vector, util_vector, encontrar);

if (posicion == -1)

cout << "\nEl valor " << encontrar

<< "no se encuentra en el vector";

else

cout << "\nEl valor " << encontrar

<< "se encuentra en la posici\’on " << posicion;

}

<Definicion de funciones>

Tema 4. Vectores y Matrices 32

Algoritmo:

Repite mientras !encontrado y tengas componentes v[i]

if v[i] == buscado

encontrado = true

else

i++

if encontrado

imprime posicion :-((

else

imprime "no se encuentra" :-((

Algoritmo:

Repite mientras !encontrado y tengas componentes v[i]

if v[i] == buscado

encontrado = true

else

i++

if encontrado

return i

else

return -1

Tema 4. Vectores y Matrices 33

Primera aproximación.

int BuscaSec(const double v[], int util_v, double buscado){

int i, posicion;

bool encontrado;

i=0;

encontrado=false;

while ((i<util_v) && !encontrado)

if (v[i] == buscado){

posicion=i;

encontrado=true;

}

else

i++;

if (encontrado)

return posicion;

else

return -1;

}

Tema 4. Vectores y Matrices 34

Segunda aproximación.

int BuscaSec(const double v[], int util_v, double buscado){

int i;

for (i=0; i<util_v && v[i]!=buscado; i++)

;

if (i==util_v)

return -1;

else

return i;

}

Tema 4. Vectores y Matrices 35

A veces, podemos estar interesados en buscar entre una com-ponente izquierda y otra derecha, ambas inclusive.

int BuscaSec_entre (double v[], int izda, int dcha,

double buscado){

int i;

bool encontrado = false;

for (i=izda ; i<=dcha && !encontrado ; i++)

encontrado = (v[i]==buscado);

if (encontrado)

return i-1;

else

return -1;

}

Tema 4. Vectores y Matrices 36

4.1.5.2. BÚSQUEDA BINARIA

Precondición Búsqueda Binaria: Se aplica sobre un vectorordenado.

La cabecera no cambia.

int BuscaBinaria(const double v[], int util_v,

double buscado)

Nota. El nombre del identificador de la función refleja queno es una búsqueda cualquiera, sino que necesita una pre-condición.

Algoritmo:

• El elemento a buscar se compara con el elemento queocupa la mitad del vector.

• Si coinciden, se habrá encontrado el elemento.

• En otro caso, se determina la mitad del vector en la quepuede encontrarse.

• Se repite el proceso con la mitad correspondiente.

Tema 4. Vectores y Matrices 37

Ejemplo. Buscar el 40

60402518

5 6 7 8

dch=8izq=5

centro=6

6040

7 8

dch=8izq=7

centro=7

0 1 2 3 4 5 7 86

−8 60402518124 5 9

centro=4

dch=8izq=0

40 > 25

40 > 12

Encontrado

Tema 4. Vectores y Matrices 38

int BuscaBinaria(const double v[], int util_v,

double buscado) {

int izq, dch, centro;

izq = 0;

dch = util_v-1;

centro = (izq+dch)/2;

while ((izq<=dch) && (v[centro]!=buscado)) {

if (buscado < v[centro])

dch = centro-1;

else

izq = centro+1;

centro = (izq+dch)/2;

}

if (izq>dch)

return -1;

else

return centro;

}

Tema 4. Vectores y Matrices 39

4.1.6. CONSTRUCCIÓN DE VECTORES EN UNA FUN-CIÓN

Supongamos que queremos que un módulo construya un vec-tor. Éste no puede ser local ya que al terminar el módulo suzona de memoria desaparece.

Debemos declarar dicho vector en el main (en general, en lafunción que realiza la llamada) y pasarlo como parámetro:

Ejemplo. Crear un vector con las componentes pares de otro.

#include <iostream>

using namespace std;

void LecturaVectorInt (int v[], int util_v);

void ImprimeVectorInt (int v[], int util_v);

void SoloPares(const int v[], int util_v, int vPares[],

int &util_vPares);

int main(){

const int DIM=100;

int vector[DIM], salida[DIM];

int util_vector = 7, util_salida;

LecturaVectorDouble(vector, util_vector);

SoloPares(vector, util_vector, salida, util_salida);

ImprimeVectorDouble(salida, util_salida);

}

Tema 4. Vectores y Matrices 40

<Definicion de LecturaVectorInt e ImprimeVectorInt>

void SoloPares(const int v[], int util_v, int vPares[],

int &util_vPares){

util_vPares=0;

for (int i=0; i<util_v; i++)

if ((v[i]%2) == 0){

vPares[util_vPares]=v[i];

util_vPares++;

}

}

Tema 4. Vectores y Matrices 41

Ejemplo. Quitar los elementos repetidos de un vector, guardan-do el resultado en otro vector.

#include <iostream>

using namespace std;

void QuitaRepetidos (const double original[],

int util_original,

double destino[],

int &util_destino);

void LecturaVectorDouble (double v[], int util_v);

void ImprimeVectorDouble (double v[], int util_v);

int main(){

const int DIM =100;

int vector[DIM], salida[DIM], util_vector = 7, util_salida;

LecturaVectorDouble(vector, util_vector);

QuitaRepetidos(vector, util_vector, salida, util_salida);

ImprimeVectorDouble(salida, util_salida);

}

<Definicion de funciones>

Tema 4. Vectores y Matrices 42

Algoritmo:

destino[0]=original[0]

Recorrer todas las componentes i de original

Si original[i] se encuentra en destino

i++

Si no

Añadir original[i] a destino

Incrementar util_destino

i++

Como se repite i++, podemos sacarlo del condicional. Por lotanto, el primero se queda vacío, y rescribimos el algoritmocomo sigue:

destino[0]=original[0]

Recorrer todas las componentes i de original

Si original[i] NO se encuentra en destino

Añadir original[i] a destino

Incrementar util_destino

i++

Tema 4. Vectores y Matrices 43

void QuitaRepetidos (const double original[],

int util_original,

double destino[],

int &util_destino){

bool encontrado;

util_destino = 0;

for (int i=0 ; i<util_original ; i++){

encontrado = false;

for (int j=0 ; (j<util_destino) && !encontrado ; j++){

if (original[i] == destino[j])

encontrado = true;

}

if (!encontrado){

destino[util_destino] = original[i];

util_destino++;

}

}

}

Tema 4. Vectores y Matrices 44

4.1.7. TRABAJANDO CON VECTORES LOCALES

Ejemplo. Calculad la moda de un vector de enteros, es decir,el elemento que más se repite. La moda de (4,2,1,2,3,2,5,1)

sería el 2.Para hacer los cómputos, vamos a usar un vector de repetidos.¿Cómo declaramos el vector local repetidos?

a) double Moda(double v[], int util_v){

double repetidos[util_v];

.............

Imposible: no podemos dimensionar con una variable.

b) double Moda(double v[], int util_v){

const int DIM = util_v;

double repetidos[DIM];

.............

Imposible: no podemos inicializar una constante con unavariable.

c) double Moda(double v[], int util_v){

double repetidos[100];

.............

¿y por qué no 200?

Tema 4. Vectores y Matrices 45

d) double Moda(double v[], int util_v){

double repetidos[DIM];

.............

}

int main(){

const int DIM = 100;

double vector[DIM];

.......

}

Error de compilación. DIM no se conoce dentro de Moda

e) const int DIM = 100;

double Moda(double v[], int util_v){

double repetidos[DIM];

.............

}

int main(){

double vector[DIM];

.............

}

Es la única solución.

Inconveniente: no podemos separar la definición de Moda

de la definición de la constante global DIM.

Solución: se verá cuando veamos memoria dinámica.

Tema 4. Vectores y Matrices 46

Vamos a calcular el conteo de la moda (su frecuencia) en lamisma función:

#include <iostream>

using namespace std;

const int DIM = 20;

void ModaVector(double v[], int util_v,

double &moda, int &conteo_moda);

int main(){

double notas[DIM] = {1,2,4,2,3,2,5,5,5,2};

double moda_notas;

int conteo_moda_notas;

ModaVector(notas, 10, moda_notas, conteo_moda_notas);

cout << moda_notas << " - " << conteo_moda_notas;

}

<Definicion de ModaVector>

Algoritmo.El vector local repetidos, se usa para almacenar las compo-nentes que ya se han recorrido

Recorrer todos los elementos v[i] del vector

Si v[i] no esta en repetidos => contamos las

apariciones de v[i] en v (desde i hacia la dcha)

Si v[i] esta en repetidos => ya lo hemos procesado.

No hacemos nada

Tema 4. Vectores y Matrices 47

void ModaVector(double v[], int util_v,

double &moda, int &conteo_moda){

double repetidos[DIM];

int pos_enc, conteo_parcial, util_repetidos;

bool seguir;

repetidos[0] = v[0]; moda = v[0]; conteo_moda = 1;

util_repetidos = 1;

for (int i=1 ; i<util_v ; i++){

if (-1 == BuscaSec_entre (repetidos, 0,

util_repetidos-1, v[i])){

util_repetidos++;

seguir=true; conteo_parcial = 0; pos_enc = i;

while (seguir){

pos_enc = BuscaSec_entre(v, pos_enc+1,

util_v-1, v[i]);

if (-1==pos_enc)

seguir = false;

else

conteo_parcial++;

}

if (conteo_parcial > conteo_moda){

conteo_moda = conteo_parcial;

moda = v[i];

}

}

}

}

Tema 4. Vectores y Matrices 48

4.1.8. ALGORITMOS DE ORDENACIÓN

La ordenación es un procedimiento mediante el cual se dispo-nen los elementos de un vector en un orden especificado, talcomo orden alfabético u orden numérico.

Existen dos tipos de ordenación:

Ordenación interna. Todos los datos están en memoria prin-cipal durante el proceso de ordenación.

• Inserción.

• Selección.

• Intercambio.

Ordenación externa. Parte de los datos a ordenar están enmemoria externa mientras que otra parte está en memoriaprincipal siendo ordenada. Se verán en MP2.

Tema 4. Vectores y Matrices 49

4.1.8.1. ORDENACIÓN POR SELECCIÓN

Ejemplo. Calcular el mínimo elemento de un vector.

v = (2,4,7,1,8,?,?,?)

Mejor que devolver el elemento 1, devolvemos su posición 3

Algoritmo:

Inicializar minimo = v[0]

Recorrer todas las componentes v[i] (i>0)

Si v[i] es menor que minimo

Actualizar minimo

Recordar posicion

i++

int PosMinimo (const double v[], int util_v){

int posicion_minimo;

double minimo;

minimo = v[0];

posicion_minimo = 0;

for (int i=1; i<util_v ; i++)

if (v[i] < minimo){

minimo = v[i];

posicion_minimo = i;

}

return posicion_minimo;

}

Tema 4. Vectores y Matrices 50

Ejemplo. Calcular el mínimo elemento de un vector, pero pa-sándole al módulo las componentes izda y dcha donde se quie-re trabajar.

v = (6,8,7,2,4,9,3,1,?,?) izda=2 , dcha=5

PosMinimo(v,izda,dcha) devuelve la posición 3 (índice de v)

Precondición: 0 <= izda <= dcha <= util_v-1

int PosMinimo (const double v[], int izda, int dcha){

int posicion_minimo;

double minimo;

minimo = v[izda];

posicion_minimo = izda;

for (int i=izda+1 ; i <= dcha ; i++)

if (v[i] < minimo){

minimo = v[i];

posicion_minimo = i;

}

return posicion_minimo;

}

Tema 4. Vectores y Matrices 51

Ordenación por selección.

En cada pasada, se selecciona el elemento más pequeño delsubvector no ordenado y se intercambia con el primer elemen-to de este mismo subvector.

SubvectorOrdenado

SubvectorNo Ordenado

0 j k Util−1

Menor elemento de k a Util−1

Algoritmo:

Recorrer todos los elementos v[i] de v

Hallar la posicion pos_min del menor elemento

del subvector delimitado por las componentes

[i,util_v-1] ¡ambas inclusive!

Intercambiar v[i] con v[pos_min]

En el bucle principal no es necesario recorrer todos los ele-mentos de v, ya que si sólo queda 1 componente el vector es-tá ordenado. Por lo tanto, el bucle principal será de la formai<util_v-1

Tema 4. Vectores y Matrices 52

7823 45 8 32 56

8 23 3245 78 56

238 32 78 45 56

8 5623 32 45 78

8 7823 32 45 56

8 45 23 32 5678

Tras la pasada 5

Tras la pasada 4

Tras la pasada 3

Tras la pasada 2

Tras la pasada 1

Vector Original

Tema 4. Vectores y Matrices 53

#include <iostream>

using namespace std;

void ImprimeVectorDouble(double v[], int util_v){

.....................

}

void LecturaVectorDouble (double v[], int util_v){

.....................

}

int PosMinimo (const double v[], int izda, int dcha){

.....................

}

void IntercambiaDouble (double &a, double &b){

double aux;

aux = a;

a = b;

b = aux;

}

void OrdSeleccion (double v[], int util_v){

int pos_min;

for (int i=0 ; i<util_v-1 ; i++){

pos_min = PosMinimo(v, i, util_v-1);

IntercambiaDouble(v[i],v[pos_min]);

}

}

Tema 4. Vectores y Matrices 54

int main(){

double vector[] = {7,4,8,1};

int util_vector = 4;

LecturaVectorDouble(vector, util_vector);

OrdSeleccion (vector, util_vector);

ImprimeVectorDouble(vector, util_vector);

}

Tema 4. Vectores y Matrices 55

Versión sin llamadas a funciones:

void OrdSeleccion(double v[], int util_v){

int i, j, pos_min;

double aux;

for (i=0; i<util_v-1; i++){

pos_min=i;

for (j=i+1; j<util_v; j++)

if (v[j] < v[pos_min])

pos_min=j;

aux = v[i];

v[i] = v[pos_min];

v[pos_min] = aux;

}

}

Compromiso reutilización versus eficiencia. Usualmente pre-valecerá la reutilización. Pero si tenemos que construir un mó-dulo, verificando alguna de estas restricciones:

que realice muchas operaciones

que sea utilizable en otros programas

merece la pena construirlo eficientemente.

Tema 4. Vectores y Matrices 56

4.1.8.2. ORDENACIÓN POR INSERCIÓN

Ejemplo. Insertar un elemento en una posición concreta de unvector.

v = (2,7,4,8,1,?,?,?)

pos_insercion = 3

valor = 5

v = (2,7,4,5,8,1,?,?)

Algoritmo (primera versión):

Recorrer las componentes posteriores a pos_insercion

hasta llegar al final de v

v[i] = v[i-1];

i++;

v[pos_insercion] = valor;

Algoritmo (versión correcta):

Recorrer las componentes desde el final del vector

hasta llegar a pos_insercion

v[i] = v[i-1];

i--;

v[pos_insercion] = valor;

Tema 4. Vectores y Matrices 57

Parametrización:

void Inserta(double v[], int &util_v,

int pos_insercion, double valor)

Importante:

Hay que incrementar util_v en 1. Por eso se pasa por re-ferencia.

Precondición: util_v < DIM_V

void Inserta(double v[], int &util_v,

int pos_insercion, double valor){

for (int i=util_v ; i>pos_insercion ; i--)

v[i] = v[i-1];

v[pos_insercion] = valor;

util_v++;

}

int main(){

const int DIM_VECTOR = 8;

double vector[DIM_VECTOR] = {2,7,4,8,1};

int util_vector = 5;

Inserta(vector, util_vector, 3, 5);

}

Tema 4. Vectores y Matrices 58

Supongamos que queremos quitar la precondiciónutil_v < DIM_V

Posibles soluciones:

Declarar DIM_V como una constante global y comprobar suvalor dentro del módulo Inserta

const int DIM_VECT = 100;

void Inserta(double v[], int &util_v, int pos_insercion,

double valor, bool &error){

error = (util_v >= DIM_VECT);

if (!error){

for (int i=util_v ; i>pos_insercion ; i--)

v[i] = v[i-1];

v[pos_insercion] = valor;

util_v++;

}

}

int main(){

int vect[DIM_VECT];

............

Inserta(vect, util_vect, 3, 5, err);

if (err)

cout << "Número de componentes insuficiente}

else

............

}

Tema 4. Vectores y Matrices 59

Pasar la dimensión como parámetro a Inserta

void Inserta(double v[], int DIMEN, int &util_v,

int pos_insercion, double valor, bool &error){

error = (util_v >= DIMEN);

if (!error){

for (int i=util_v ; i>pos_insercion ; i--)

v[i] = v[i-1];

v[pos_insercion] = valor;

util_v++;

}

}

int main(){

const int DIM_VECT = 100;

int vect[DIM_VECT];

............

Inserta(vect, DIM_VECT, util_vect, 3, 5, err);

if (err)

cout << "Número de componentes insuficiente}

else

............

}

Tema 4. Vectores y Matrices 60

En la primera solución no podemos separar la definición de lafunción de la constante. En la segunda, aumentamos el núme-ro de parámetros.

Posiblemente, lo mejor sea olvidarnos de la precondición yusar la cabecera:

void Inserta(double v[], int &util_v,

int pos_insercion, double valor)

Ejercicio: Borrad un elemento de un vector.

Tema 4. Vectores y Matrices 61

Ejemplo. Insertad un elemento de forma ordenada en un vectorya ordenado.

v = (1,2,4,7,8,?,?,?)

valor = 5

v = (1,2,4,5,7,8,?,?)

Hay que desplazar componentes como en el ejemplo ante-rior.

La condición de parada cambia.

Algoritmo:

Recorrer las componentes desde el final del vector

hasta llegar a una componente que sea menor que el valor

v[i] = v[i-1];

i--;

v[i] = valor;

Tema 4. Vectores y Matrices 62

void InsertaOrd(double v[], int &util_v, int valor){

int i;

for (i=util_v; i>0 && valor<v[i-1]; i--)

v[i]=v[i-1];

v[i]=valor;

util_v++;

}

Ejercicio. Cread un módulo para leer 100 elementos desde te-clado, y conforme los va leyendo, vaya creando un vector or-denado.

Tema 4. Vectores y Matrices 63

Ordenación por inserción.

El vector se divide en dos subvectores: el de la izquierda orde-nado, y el de la derecha desordenado.

Cogemos el primer elemento del subvector desordenado y loinsertamos de forma ordenada en el subvector ordenado.

SubvectorOrdenado

SubvectorNo Ordenado

0 j k Util−1

INSERTAR

Importante. La componente de la posición k (primer elemen-to del subvector desordenado) será remplazada por la anterior(después de desplazar).

Algoritmo.

Ir fijando el inicio del subvector izquierda

con un contador izda desde 1 hasta util_v

Seleccionar el valor v[izda]

Insertar dicho valor de forma ordenada

en el subvector de v delimitado por [0,izda-1]

Nota. Empezamos desde 1, ya que la primera componente for-ma un subvector ya ordenado.

Tema 4. Vectores y Matrices 64

45 8 32 56

23 5678 8 32

56

8 78

45

23 45 78 8 32 56

8 23 45 78 32 56

8 23 32 45 78

23 32 45 56

23 78 Vector Original

Tras la pasada 1

Tras la pasada 2

Tras la pasada 3

Tras la pasada 4

Tras la pasada 5

Tema 4. Vectores y Matrices 65

void OrdInsercion (double v[], int util_v){

int izda;

double valor;

for (izda=1; izda<util_v; izda++){

valor = v[izda];

InsertaOrd(v, izda, valor); // <- Modifica v[izda]!

}

}

Obviamente, no es necesaria la variable valor:

void OrdInsercion (double v[], int util_v){

int izda;

for (izda=1; izda<util_v; izda++)

InsertaOrd(v, izda, v[izda]);

}

Tema 4. Vectores y Matrices 66

Sin embargo, el algoritmo no funciona correctamente!Razón: izda se pasa por referencia y en cada iteración se mo-difica en la llamada a InsertaOrd.

Solución:

void OrdInsercion (double v[], int util_v){

int izda = 1;

while (izda < util_v)

InsertaOrd(v, izda, v[izda]);

}

Sin llamadas a funciones:

void OrdInsercion (double v[], int util_v){

int izda, i;

double valor;

for (izda=1; izda<util_v; izda++){

valor = v[izda];

for (i=izda; i>0 && valor<v[i-1]; i--)

v[i] = v[i-1];

v[i] = valor;

}

}

Tema 4. Vectores y Matrices 67

4.1.8.3. ORDENACIÓN POR INTERCAMBIO DIRECTO (MÉTODO DE

LA BURBUJA)

Al igual que antes, a la izquierda se va dejando un subvectorordenado.

Desde el final y hacia atrás, se van comparando elementos dosa dos y se deja a la izquierda el más pequeño (hay que inter-cambiarlos).

Tema 4. Vectores y Matrices 68

Ejemplo (Primera Pasada)

7823 45 8 32 56

7823 45 8 32 56

7823 45 8 32 56

23 32 5645788

32 5645788 23

No intercambiar

No intercambiar

Intercambiar

Vector Original

7823 32 568 45

Intercambiar

Intercambiar

Proceso

Durante Pasada 1

Tras la pasada 1

Tema 4. Vectores y Matrices 69

Ejemplo (Resto de Pasadas)

8 7823 32 45 56

8

7823 45 8 32 56

8 23

238 32

8 23 32 45

32 78 45 56

7845 56

56 78

23 78 45 32 56

Tras la pasada 5

Tras la pasada 4

Tras la pasada 3

Tras la pasada 2

Tras la pasada 1

Vector Original

Tema 4. Vectores y Matrices 70

Algoritmo

Ir fijando el inicio del subvector izquierda

con un contador izda desde 0 hasta util_v

Recorrer el vector de la derecha desde

el final (util_v) hasta el principio (izda)

con un contador i

Si v[i] < v[i-1] intercambiarlos

SubvectorOrdenado

SubvectorNo Ordenado

0 j k Util−1

El menor se desplaza hacia k

Tema 4. Vectores y Matrices 71

Primera Aproximación

void OrdBurbuja (double v[], int util_v){

int izda, i;

for (izda=0; izda<util_v; izda++)

for (i=util_v-1 ; i>izda ; i--)

if (v[i] < v[i-1])

IntercambiaDouble(v[i], v[i-1]);

}

Mejora. Si en una pasada del bucle más interno no se produceningún intercambio, el vector ya está ordenado. Lo comproba-mos con una variable lógica.

Tema 4. Vectores y Matrices 72

Segunda Aproximación

void OrdBurbuja (double v[], int util_v){

int izda, i;

bool cambio;

cambio= true;

for (izda=0; izda<util_v && cambio; izda++){

cambio=false;

for (i=util_v-1 ; i>izda ; i--)

if (v[i] < v[i-1]){

IntercambiaDouble(v[i], v[i-1]);

cambio=true;

}

}

}

Tema 4. Vectores y Matrices 73

4.1.9. CADENAS DE CARACTERES (CSTRING)

4.1.9.1. INTRODUCCIÓN

Una cadena de caracteres es un secuencia ordenada de carac-teres de longitud variable. Permiten trabajar con datos comoapellidos, direcciones, etc. Recordemos que los literales de ca-dena de caracteres se representan entre comillas dobles.

cout << "Esto es un literal de cadena de caracteres";

En C++ podemos encontrar dos alternativas para representareste tipo de información:

El tipo string que son las cadenas de caracteres propias deC++ que se introdujeron en el primer tema y se verán conmás detalle en MP2.

string mensaje;

mensaje = "Esto es un literal de cadena de caracteres";

cout << mensaje;

Un vector de char. Es la forma heredada de C.

char mensaje[10];

Para delimitar el final del vector NO se usa la típica varia-ble util_mensaje sino un carácter especial ’\0’ que se leasignará a la última componente.’\0’ se conoce como marca de fin de cadena o carácternulo

Tema 4. Vectores y Matrices 74

La asignación se realiza componente a componente, como cual-quier otro vector.

char mensaje[10];

mensaje[0] = ’H’;

mensaje[1] = ’o’;

mensaje[2] = ’l’;

mensaje[3] = ’a’;

mensaje[4] = ’\0’;

mensaje = "Hola"; // <- Error de compilación.

// mensaje es un vector !!

’H’ ’o’ ’l’ ’a’ ’\0’ ? ? ? ? ?

A los vectores de char con el carácter nulo como terminador seles suele llamar cstring (pero no es un tipo propio del lenguaje)

En general, declararemos:

char <identificador> [<tamaño>];

dónde el tamaño ha de ser el número de caracteres más uno(para almacenar el carácter nulo)

char mensaje[4];

mensaje[0] = ’H’;

mensaje[1] = ’o’;

mensaje[2] = ’l’;

mensaje[3] = ’a’;

mensaje[4] = ’\0’; // Error lógico :-(

Tema 4. Vectores y Matrices 75

char mensaje[5];

mensaje[0] = ’H’;

mensaje[1] = ’o’;

mensaje[2] = ’l’;

mensaje[3] = ’a’;

mensaje[4] = ’\0’; // :-)

4.1.9.2. INICIALIZACIÓN Y ASIGNACIÓN

Al declarar un cstring, podemos darle un valor inicial comocualquier otro vector:

char mensaje[5] = {’H’,’o’,’l’,’a’,’\0’};

char no_cabe[4] = {’H’,’o’,’l’,’a’,’\0’}; // Warning o error

Incluso podemos suprimir la dimensión (esto es válido paracualquier vector, siempre que lo inicialicemos en la declara-ción)

char mensaje[] = {’H’,’o’,’l’,’a’,’\0’};

El compilador reserva automáticamente 5 componentes.

Para los vectores de char, C++ permite inicializarlos con unliteral de cadena de caracteres:

char mensaje[5] = "Hola";

char mensaje[] = "Hola";

char no_cabe[4] = "Hola"; // <- Warning o error

El compilador pondrá automáticamente el carácter nulo al final.

Tema 4. Vectores y Matrices 76

Esta asignación sólo puede hacerse en la inicialización:

char mensaje[5] = "Hola";

char otro_mensaje[5];

otro_mensaje = "Hola"; // Error de compilación

// vector = literal cadena caracteres

otro_mensaje = mensaje; // Error de compilación

// Asignación entre vectores

4.1.9.3. USO DE FUNCIONES

Como cualquier otro vector (salvo que no pasamos las compo-nentes útiles)

int longitud(const char cadena[]){

int i=0;

while (cadena[i]!=’\0’);

i++;

return i;

}

int main(){

char mensaje[] = "Hola";

cout << longitud(mensaje); // Imprime 4

}

Tema 4. Vectores y Matrices 77

Ejercicio: Construir una función que dada una cadena s y uncarácter c devuelva la posición que ocupa la primera ocurren-cia del carácter c en la cadena s. Devolver -1 si el carácter noestá en la cadena.

Tema 4. Vectores y Matrices 78

4.1.9.4. OPERADOR DE ASIGNACIÓN ENTRE CSTRING

char mensaje[5] = "Hola";

char otro_mensaje[5];

otro_mensaje = mensaje; // Error de compilación

// Asignación entre vectores!!

void CopiaCadena(char destino[], const char origen[]){

for (int i=0 ; v[i]!=’\0’; i++)

destino[i] = origen[i];

}

int main(){

char mensaje[5] = "Hola";

char otro_mensaje[5];

CopiaCadena(otro_mensaje, mensaje); // :-)

.....

}

int main(){

char mensaje[5];

char otro_mensaje[5];

mensaje[0] = ’H’;

CopiaCadena(otro_mensaje, mensaje); // Error lógico grave

Tema 4. Vectores y Matrices 79

La biblioteca (cstring) contiene la definición de ésta y muchasotras funciones para trabajar con vectores de char.

strcpy(char cadena1, const char cadena2);

#include <cstring>

int main(){

char mensaje[5] = "Hola";

char otro_mensaje[5];

strcpy(otro_mensaje, mensaje);

.....

}

IMPORTANTE: Es tarea del programador asegurar que el tama-ño de la cadena destino es suficiente para realizar la copia dela cadena fuente.

Otras funciones de la biblioteca cstring:

int strlen(const char s[]) que devuelve la longitud de lacadena s.

strcat(char s1[], const char s2[]) que concatena las ca-denas s1 y s2 y el resultado se almacena en s1.

int strcmp(const char s1[], const char s2[]) que compa-ra las cadenas s1 y s2. Si la cadena s1 es menor que s2 de-vuelve un valor menor que cero, si son iguales devuelve 0y en otro caso devuelve un valor mayor que cero.

Tema 4. Vectores y Matrices 80

4.1.9.5. LECTURA DE CADENAS CSTRING

Se pueden utilizar las operaciones de lectura y escritura yaconocidas:

char nombre[30];

cout << "Introduce tu nombre: ";

cin >> nombre;

cout << "El nombre introducido es: " << nombre;

Sin embargo, si la cadena que se desea introducir contieneseparadores (espacios y/o tabuladores), la variable contendrásólo los caracteres hasta el primer separador.

Si se desea introducir una cadena con estos separadores esnecesario hacerlo usando:

cin.getline (<buffer>,<longitud>)

donde <buffer> es un vector de char y <longitud> es el espaciodisponible en el vector.

Tema 4. Vectores y Matrices 81

const int TAMANO=30; char nombre[TAMANO];

int edad;

char direccion[TAMANO];

cout << "Introduce tu nombre: ";

cin.getline (nombre,TAMANO);

cout << "El nombre introducido es: " << nombre;

cout <<"Introduce tu edad: ";

cin >> edad;

cout <<"Introduce tu direccion: ";

cin.getline(direccion,TAMANO);

...

Problema: Cuando se lee edad se queda el salto de linea en elbuffer y cin.getline (direccion,TAMANO) lee ese salto de líneay, como ya ha leido un salto de línea, termina y devuelve lacadena vacia.

Tema 4. Vectores y Matrices 82

Solución: Crear una función LeerLinea que evite las líneas va-cías:

void LeerLinea(char c[], int maxlongitud)

{

do {

cin.getline(c,maxlongitud);

} while (c[0]==’\0’); // evita las cadenas vacias

}

...

cout << "Introduce tu nombre: ";

LeerLinea (nombre,TAMANO);

cout << "Introduce tu edad: ";

cin >> edad;

cout << "Introduce tu direccion: ";

LeerLinea (direccion,TAMANO); ...

Tema 4. Vectores y Matrices 83

4.2. MATRICES

4.2.1. INTRODUCCIÓN

4.2.1.1. MOTIVACIÓN

Supongamos una finca rectangular dividida en parcelas. Que-remos almacenar la producción de aceitunas, en TM.

La forma natural de representar la parcelación sería usando elconcepto matemático de matriz.

4.5 5.9 1.2

9.1 0.4 5.8

Para representarlo en C++ podríamos usar un vector parcela:

9.1 0.4 5.8 4.5 5.9 1.2

pero la forma de identificar cada parcela (por ejemplo parcela[4])es poco intuitiva para el programador.

Tema 4. Vectores y Matrices 84

4.2.1.2. DECLARACIÓN DEL TIPO MATRIZ

<tipo de dato> <identificador> [DIM_FIL][DIM_COL];

Como con los vectores, el tipo base de la matriz es el mismopara todas las componentes, ambas dimensiones han de serde tipo entero, y comienzan en cero.

int main(){

const int DIM_FIL_parcela = 2;

const int DIM_COL_parcela = 3;

double parcela[DIM_FIL_parcela][DIM_COL_parcela];

}

Tema 4. Vectores y Matrices 85

4.2.1.3. INICIALIZACIÓN

Al igual que con los vectores, podemos inicializar una matrizen la misma declaración. La forma segura es poner entre llaveslos valores de cada fila.

int m[2][3]={{1,2,3},{4,5,6}}; // m tendra: 1 2 3

// 4 5 6

Si no hay suficientes inicializadores para una fila determinada,los elementos restantes se inicializan a 0.

int mat[2][2]={{1},{3,4}}; // Mat tendra: 1 0

// 3 4

Si se eliminan los corchetes que encierran cada fila, se iniciali-zan los elementos de la primera fila y después los de la segun-da, y así sucesivamente.

int A[2][3]={1, 2, 3, 4, 5} // A tendra: 1 2 4

// 4 5 0

Tema 4. Vectores y Matrices 86

4.2.2. OPERACIONES CON MATRICES

4.2.2.1. ACCESO

<Ident> [<ind1>] [<ind2>]

0 ≤ indi < Dimi

<Ident> [<ind1>] [<ind2>] es una variable más del programa yse comporta como cualquier variable del tipo de dato base dela matriz.

4.2.2.2. ASIGNACIÓN, LECTURA Y ESCRITURA

En la declaración de la matriz se pueden asignar valores a todala matriz. Posteriormente, no es posible: es necesario accedera cada componente independientemente.

Por ejemplo, para asignar una expresión a una celda:

<Ident> [<ind1>] [<ind2>] = <Expresión>;

<Expresión> ha de ser del mismo tipo de dato que el tipo basede la matriz.

Tema 4. Vectores y Matrices 87

Ejemplo:

int main(){

const int DIM_FIL_parcela = 2;

const int DIM_COL_parcela = 3;

double parcela[DIM_FIL_parcela][DIM_COL_parcela];

int valor = 7;

parcela[0][0] = 4.5 // Correcto;

parcela[0][1] = 5.9 // Correcto;

parcela[2][0] = 7.2 // Error logico: Fila 2 No existe.

parcela[0][3] = 7.2 // Error logico: Columna 3 No existe.

parcela[0][0] = 4 // Correcto:

// Casting automatico: double=int

}

Tema 4. Vectores y Matrices 88

4.2.3. GESTIÓN DE COMPONENTES ÚTILES CON MA-TRICES

Por cada dimensión necesitamos gestionar una variable queindique el número de componentes útiles.

#include <iostream>

using namespace std;

int main(){

const int DIM_FIL_parcela=5, DIM_COL_parcela=8;

int utilFil_parcela, utilCol_parcela;

int fil, col;

double parcela[DIM_FIL_parcela][DIM_COL_parcela];

double produccion;

utilFil_parcela=2;

utilCol_parcela=3;

for (fil=0 ; fil<utilFil_parcela ; fil++)

for (col=0 ; col<utilCol_parcela ; col++){

cout << "Introduce produccion en TM de la parcela "

<< fil << "," << col;

cin >> produccion;

parcela[fil][col]= produccion;

}

cout << "\nDatos introducidos:\n";

Tema 4. Vectores y Matrices 89

for (fil=0 ; fil<utilFil_parcela ; fil++){

for (col=0 ; col<utilCol_parcela ; col++){

cout << "\nProducci\’on en TM de la parcela "

<< fil << "," << col << " --> ";

cout << parcela[fil][col];

}

cout << endl;

}

}

Nota. Podemos poner directamente: cin >> parcela[fil][col]

Tema 4. Vectores y Matrices 90

Ejemplo. Buscar un elemento en una matriz.

#include <iostream>

using namespace std;

int main(){

const int DIM_FIL_m = 2, DIM_COL_m = 3;

double m[DIM_FIL_m][DIM_COL_m];

int Filencontrado, Colencontrado, utilFil_m,

utilCol_m, fil, col;

double buscado;

bool encontrado;

do{

cout << "Introducir el numero de filas: ";

cin >> utilFil_m;

}while ( (utilFil_m<1) || (utilFil_m>DIM_FIL_m) );

do{

cout << "Introducir el numero de columnas: ";

cin >> utilCol_m;

}while ( (utilCol_m<1) || (utilCol_m>DIM_COL_m) );

Tema 4. Vectores y Matrices 91

for (fil=0 ; fil<utilFil_m ; fil++)

for (col=0 ; col<utilCol_m ; col++){

cout << "Introducir el elemento ("

<< fil << "," << col << "): ";

cin >> m[fil][col];

}

cout << "\nIntroduzca elemento a buscar: ";

cin >> buscado;

encontrado=false;

for (fil=0; !encontrado && (fil<utilFil_m) ; fil++){

for (col=0; !encontrado && (col<utilCol_m) ; col++)

if (m[fil][col] == buscado){

encontrado = true;

Filencontrado = fil;

Colencontrado = col;

}

}

}

if (encontrado)

cout << "\nencontrado en la posici\’on "

<< Filencontrado << "," << Colencontrado << endl;

else

cout << "\nElemento no encontrado\n";

}

Importante: la variable encontrado ha de ser la misma en losdos bucles while.

Tema 4. Vectores y Matrices 92

4.2.4. MATRICES DE VARIAS DIMENSIONES

Podemos declarar tantas dimensiones como queramos. Sóloes necesario añadir más corchetes.

Por ejemplo, para representar la producción de una finca di-vidida en 2×3 parcelas, y dónde en cada parcela se practicancinco tipos de cultivos, definiríamos:

const int DIV_HOR = 2,

DIV_VERT = 3,

TOTAL_CULTIVOS = 5;

double parcela[DIV_HOR][DIV_VERT][TOTAL_CULTIVOS];

// Asignación al primer cultivo de la parcela 1,2

parcela[1][2][0] = 4.5;

Tema 4. Vectores y Matrices 93

4.2.5. MODULARIZACIÓN CON MATRICES

Todas las posiciones de una matriz están realmente contiguasen memoria. La representación exacta depende del lenguaje.En C++ se hace por filas:

4.5 5.9 1.2

m

9.1 0.4 5.8

m

9.1 0.4 5.8 4.5 5.9 1.2

Para calcular dónde se encuentra la componente m[1][2] elcompilador debe pasar a la segunda fila. Lo consigue trasla-dándose tantas posiciones como diga DIM_COL_m, a partir delcomienzo de m. Una vez ahí, salta 2 posiciones y ya está enm[1][2].

Conclusión: Para saber dónde está m[i][j], el compilador ne-cesita saber cuánto vale DIM_COL_m, pero no DIM_FIL_m. Paraello, da tantos saltos como indique la expresión:

i*DIM_COL_m + j

Por eso, para pasar una matriz bidimensional hay que especi-ficar en la cabecera DIM_COL_m

void ImprimeMatriz(double m[][DIM_COL_m] , int utilFil_m,

int utilCol_m)

Tema 4. Vectores y Matrices 94

Pero entonces, DIM_COL_m no puede ser local a main. Debe seruna constante global :-(. No hay otra solución.

#include <iostream>

using namespace std;

const int DIM_FIL=3, DIM_COL=2;

void ImprimeMatriz(const double m[][DIM_COL] , int utilFil,

int utilCol){

for (int fil=0 ; fil<utilFil ; fil++){

for (int col=0 ; col<utilCol ; col++)

cout << m[fil][col] << " ";

cout << endl;

}

}

int main(){

double parcela[DIM_FIL][DIM_COL]={{5.4,3},{6,7},{1,2.4}};

int utilFil_parcela=3, utilCol_parcela=2;

ImprimeMatriz(parcela , utilFil_parcela , utilCol_parcela);

}

Tema 4. Vectores y Matrices 95

En general, para una matriz n-dimensional hay que especificartodas las dimensiones excepto la primera.

const int DIM_FIL=3, DIM_COL=2, DimProf=5;

void ImprimeMatriz(const double m[][DIM_COL][DimProf] ,

int utilFil, int utilCol, int utilProf){

for (int fil=0 ; fil<utilFil ; fil++){

for (int col=0 ; col<utilCol ; col++){

for (int prof=0 ; prof<utilProf ; prof++)

cout << m[fil][col][prof] << " ";

cout << endl;

}

cout << endl;

}

}

Importante: éste es un ejemplo de la necesidad de usar cons-tantes globales. Sin embargo, posiblemente sea el único casodonde lo hagamos.

Tema 4. Vectores y Matrices 96

Ejemplo: Buscar un elemento en una matriz.

#include <iostream>

using namespace std;

const int DIM_FIL = 2; const int DIM_COL = 3;

void BuscaEnMatriz(const double m[][DIM_COL],

int utilFil, int utilCol,

double buscado, bool &encontrado,

int &fil_encontrado, int &col_encontrado){

int fil;

int col;

encontrado=false;

for (fil=0; !encontrado && (fil<utilFil) ; fil++){

for (col=0; !encontrado && (col<utilCol) ; col++)

if (m[fil][col] == buscado){

encontrado = true;

fil_encontrado = fil;

col_encontrado = col;

}

}

}

int main(){

double m[DIM_FIL][DIM_COL];

int fil, col, utilFil_m, utilCol_m,

posFil, posCol;

double elemento;

Tema 4. Vectores y Matrices 97

bool encontrado;

do{

cout << "Introduce el numero de filas: ";

cin >> utilFil_m;

}while ( (utilFil_m<1) || (utilFil_m>DIM_FIL) );

do{

cout << "Introduce el numero de columnas: ";

cin >> utilCol_m;

}while ( (utilCol_m<1) || (utilCol_m>DIM_COL) );

for (fil=0; fil<utilFil_m; fil++)

for (col=0; col<utilCol_m; col++){

cout << "\nIntroduce el " << fil << "," << col <<": ";

cin >> m[fil][col];

}

cout << "\n\nIntroduzca elemento a buscar: ";

cin >> elemento;

BuscaEnMatriz(m, utilFil_m, utilCol_m, elemento,

encontrado, posFil, posCol);

if (encontrado)

cout << "\nEncontrado en la posición "

<< posFil << "," << posCol;

else

cout << "\nElemento no encontrado\n";

}

Tema 4. Vectores y Matrices 98

Ejercicio. Calcular la traspuesta de una matriz.

Tema 4. Vectores y Matrices 99

4.2.6. GESTIÓN DE FILAS DE UNA MATRIZ COMO VEC-TORES

Internamente, una matriz es una serie de posiciones contiguasen memoria. Como cada fila también es una serie de posicio-nes contiguas en memoria, podemos decir que una fila de unamatriz es un vector.

¿Cómo se llama la fila i de una matriz m? m[i]

Fila 0 -> m[0]

Fila 1 -> m[1]

Fila 2 -> m[2]

¿Cuántas componentes utilizadas tiene el vector m[i]? util_Col_m

Tema 4. Vectores y Matrices 100

Ejemplo. Ordenar la fila 3 de una matriz bidimensional.

void OrdSeleccion (double v[], int util_v){

.............

}

void ImprimeVector(const double vector[], int util_vector){

.............

}

int main(){

double m[DIM_FIL][DIM_COL];

int utilFil_m, utilCol_m,

Filencontrado, Colencontrado;

<Rellenar datos de m>

OrdSeleccion (m[3],utilCol_m);

ImprimeVector(m[3],utilCol_m);

}

Nota. Obviamente, no ocurre lo mismo con las columnas deuna matriz.

Ejercicio. Supongamos que queremos ordenar todos los ele-mentos de una matriz. Por ejemplo:

3 5 7 1 2 3

2 1 9 --> 4 5 5

5 6 4 6 7 9

¿Qué condiciones se han de dar para poder llamar simplemen-te al procedimiento de ordenación de un vector en la formaOrdSeleccion(m[0],Tope)?

Tema 4. Vectores y Matrices 101

Ejemplo. Hallar el máximo elemento de los mínimos de cadafila de una matriz.

3 5 7 3 |

2 1 9 --> 1 | --> 4

5 6 4 4 |

Primera aproximación.

Ordenar cada fila

Coger el primer elemento de cada fila

y calcular el maximo de todos ellos.

Inconvenientes:

No debemos modificar los datos originales de la matriz

Ordenar un vector es más lento que buscar el mínimo.

Segunda aproximación.

Calcular el minimo de cada fila y almacenarlo en

un vector de minimos

Calcular el maximo de dicho vector.

Notas:

El vector de mínimos tendrá tantas componentes como di-ga utilFil. Pero como no podemos dimensionar con unavariable tendremos que usar DIM_FIL

Usamos las funciones PosMinimo y PosMaximo, que ya cons-truimos en el apartado de Ordenación.

Debemos inicializar la primera componente del vector demínimos al mínimo de la primera fila.

Tema 4. Vectores y Matrices 102

double MaxMin (const double m[][DIM_COL],

int utilFil, int utilCol){

double minimos[DIM_FIL]; // <- ¡DIM_FIL ha de ser global!

int pos_minimo, pos_maximo;

for (int fil=0 ; fil<utilFil ; fil++){

pos_minimo = PosMinimo(m[fil],utilCol);

minimos[fil] = m[fil][pos_minimo];

}

pos_maximo = PosMaximo(minimos,utilFil);

return minimos[pos_maximo];

}

Mejoras:

Modificar para devolver las posiciones (fila y columna) dón-de se alcanza el valor.

No necesitamos un vector de mínimos. Podemos ir calcu-lando el máximo de los mínimos poco a poco.

Tema 4. Vectores y Matrices 103

double MaxMin (const double m[][DIM_COL],

int utilFil, int utilCol){

double maximo, minimo;

int pos_minimo, pos_maximo;

pos_minimo = PosMinimo(m[0],utilCol);

maximo = m[0][pos_minimo];

for (int fil=1 ; fil<utilFil ; fil++){

pos_minimo = PosMinimo(m[fil],utilCol);

minimo = m[fil][pos_minimo];

if (minimo > maximo)

maximo = minimo;

}

return maximo;

}

Mejoras:

En cuanto encontremos un elemento de una fila menor queel máximo hasta ese momento, podemos parar la búsque-da en esa fila.

3 5 7 3

2 --> 2 < 3 => Parar la busqueda en esta fila

5 6 4 4

top related