Ejercicios resueltos laboratorio 12 - Vectores (arrays)

Asignatura: Fundamentos de Informática
Especialidad: Electrónica - UPV/EHU
Curso académico: 2013-2014
Profesor: Ismael Etxeberria Agiriano

Se pueden consultar ejercicios similares al presente en formato de presentación.

Enunciado del ejercicio 12-000

Diseña y codifique un programa que genere un vector de números reales aleatorios del 0 al 10 (ambos inclusives) con un decimal y los ordene crecientemente.

Habrá que generar, por ejemplo, una lista de 10 números aleatorios, como se muestra en la Figura 12.1.


Figura 12.1. Vector de números aleatorios desordenados.

Tras ordenarlo, el resultado aplicado al ejemplo debería ser el mostrado en la Figura 12.2.


Figura 12.2. Vector de números aleatorios ordenados.

Generación de la lista aleatoria

Para la resolución del ejercicio propuesto vamos a necesitar la función (o macro) random definida en la stdlib.h, que tiene la forma siguiente:


int random (int n);

La macro random devuelve un número de una serie pseudo-aleatoria de distribución uniforme entre 0 y n - 1.

Para inicializar el primer valor (semilla) utilizaremos el reloj del sistema con la función (o macro) randomize (que requiere la inclusión del fichero time.h) de la forma:


void randomize (void);

En DevC++ no vienen definidas estas macros por lo que habrá que hacerlo a mano, despues de incluir stdio.h:


#include <stdlib.h>

#if !defined(randomize)
#define randomize() srand((unsigned)time(NULL))
#endif

#if !defined(random)
#define random(num)(int)(((long)rand()*(num))/(RAND_MAX+1))
#endif

En este apartado vamos a acometer el problema de generar el vector de números aleatorios y mostrarlo en pantalla.

Vamos a dividir el problema definiendo una función que genere genere un vector v de números n aleatorios:


void GenerarAleatorios (double v[], int n);

Una definición equivalente de esa función será:


void GenerarAleatorios (double *v, int n);

Es muy importante entender que aquella parte del programa que llame a esta función ha de disponer de un espacio reservado de al menos n elementos a partir de la dirección v. Además, dentro de esta función no sabemos cuántos elementos están reservados.

Definiremos similarmente una función para mostrar los n primeros elementos de un vector v en pantalla:


void MostrarVector (double *v, int n);

El programa principal que inicializa la semilla de números aleatorios, genera la lista de números aleatorios y los muestra en pantalla puede ser:


#include <stdlib.h>
#include <time.h>

void GenerarAleatorios (double v[], int n);
void MostrarVector     (double v[], int n);

void main (void)
{
  double vector[10];

  randomize ();
  GenerarAleatorios (vector, 10);
  MostrarVector (vector, 10);
}

Para generar la lista de n números aleatorios entre 0 y 10 con un decimal podemos obtener números del 0 al 100 y dividirlos entre 10. Para ello llamaremos a la macro random con 101 como parámetro.


void GenerarAleatorios (double v[], int n)
{
  int i;

  for (i = 0; i < n; i++)
    v[i] = (double) random (101) / 10.0;
}

Hemos utilizado el cast (double) que convierte el número entero devuelto por random a real y obtener el resultado real deseado, evitándose divisiones enteras. En realidad esto no es necesario ya que al especificar 10.0 el mismo compilador va a llevar a cabo esta conversión.

La función MostrarVector es sencilla:


#include <stdio.h>

void MostrarVector (double v[], int n)
{
  int i;

  for (i = 0; i < n; i++)
    printf (" %4.1f", v[i]);
  printf ("\n");
}

Ordenación y programa completo

La función de ordenación recibe un vector y lo ordena. Su prototipo puede ser:


void OrdenarVector (double v[], int n);

El programa principal que genere la lista de números aleatorios, los muestre, los ordene y los vuelva a mostrar puede ser:


#include <stdlib.h>
#include <time.h>

void GenerarAleatorios (double v[], int n);
void MostrarVector     (double v[], int n);
void OrdenarVector     (double v[], int n);

void main (void)
{
  double vector[10];

  randomize ();
  GenerarAleatorios (vector, 10);
  MostrarVector (vector, 10);
  OrdenarVector (vector, 10);
  MostrarVector (vector, 10);
}

Se puede observar que lo único que hemos añadido al programa principal del apartado anterior es la especificación del prototipo de la función de ordenación OrdenarVector, su llamada en el programa principal y el volver a mostrar en pantalla el vector, esta vez ordenado.

Para describir el algoritmo de ordenación que vamos a utilizar retomaremos el ejemplo al principio de este capítulo.


Figura 12.3. Vector de números aleatorios desordenados.

El algoritmo consistirá en colocar en primera posición el elemento más pequeño intercambiando con el actual, y así sucesivamente hasta ordenar todo el vector. No vamos a utilizar diagramas de flujo, sino que podemos decir, mediante pseudo-código:


Para i De 0 A n-2 Hacer
  j = índice del elemento más pequeño de i a n-1
  Si i ≠ j Entonces
    Intercambiar contenido de las celdas i y j

En la Figura 12.4 se muestra el estado del vector durante el proceso de ordenación.


Figura 12.4. Proceso de ordenación

El primer vector contiene los elementos tal y como se muestran en la Figura 12.3. El elemento menor del vector es 0.9 y el índice j de este elemento es el 3. Por lo tanto tendremos que intercambiar el elemento en la posición 0, 5.2, con el elemento en la posición 3, 0.9.

Consideraremos que este primer elemento está ordenado y abordaremos el algoritmo para el subvector de la posición 1 hasta la 9.

La codificación de esta función de ordenación puede ser:


int  IndiceMenor (double v[], int n);
void Intercambia (double *n1, double *n2);

void OrdenarVector (double v[], int n)
{
  int i, j;

  for (i = 0; i < n - 1; i++) { /* Para i de 0 a n - 2 */
    j = IndiceMenor (&v[i], n-i) + i;
    if (j != i)
      Intercambia (&v[i], &v[j]);
  }
}

La obtención del índice con el elemento menor de i a n-1 se hace mediante la función IndiceMenor a la que se le pasa el subvector que comienza en la posición i y tiene n-i elementos. Para obtener el índice del vector original tendremos que añadirle a la posición en el subvector el comienzo. Veamoslo con un ejemplo.

En la figura 12.5 se puede ver el estado de la ordenación para i = 5, es decir, ya hemos ordenado todos los elementos anteriores.


Figura 12.5. Estado del vector durante la ordenación

Buscaremos el índice del elemento menor del subvector que resta por ordenar, que obtendremos indicando la dirección de la celda i-ésima, como se muestra en la Figura 12.6.


Figura 12.6. Subvector por ordenar.

La función nos devolverá que el índice del elemento menor es el 1, pero en términos del vector original tendremos que sumarle i es decir, 5 por lo que j será 6.

Podemos definir una función que nos devuelva el índice del menor elemento de un vector de entre n:


int IndiceMenor (double v[], int n)
{
  int i, m;

  m = 0; /* Inicializamos el primer elemento como el menor */
  for (i = 1; i < n; i++)
    if (v[i] < v[m])
      m = i;
  return m;
}

El algoritmo para intercambiar el contenido de dos variables es conocido. Podemos codificar la función correspondiente:


void Intercambia (double *n1, double *n2)
{
  double t;

  t = *n1;
  *n1 = *n2;
  *n2 = t;
}