Estructuras de datos dinámicas


Como se escribió al inicio de este apartado tenemos estructuras de datos dinámicas, las que se constituyen en la opción a utilizar en algunos lenguajes como C++, en el que los arreglos vectoriales y matriciales son estáticos limitando el uso variable de datos. Para ello contamos con los llamados punteros o apuntadores.

Punteros o apuntadores

Llamados también punteros, los apuntadores son variables que contienen una dirección de memoria, y que corresponde a un dato o a una variable que contiene ese dato.

Operadores para trabajar con apuntadores

Existen dos operadores para poder trabajar con punteros, sin ellos es imposible utilizar este tipo de datos. Estos son el “&” llamado ampersand, y el “*” llamado asterisco. Estos operadores tienen asignadas funciones muy específicas para cada uno, en tal sentido se utilizan según se necesite. Si anteponemos al identificador de la variable un signo & estamos indicando que utilizamos la dirección de memoria de dicha variable, por ello se le suele llamara operador de dirección.

En el caso del operador “*”, este utiliza la dirección de una variable y retorna el valor almacenado en esa posición de memoria, por tal motivo se le acostumbra llamar operador de indirección.

Declaración de apuntadores

La sintaxis para declarar en puntero es:

tipo *identificador

De esta forma se declara que la variable contiene una dirección de memoria, que puede ser referenciada, donde tipo puede ser cualquier tipo ya sea entero, real, carácter o cadena, por ejemplo, y éste define sí y sólo sí el tipo de variable al que va a apuntar el puntero.

El nombre de la variable va después del modificador u operador de indirección *, el que nos diría en un seudo lenguaje: “puntero hacia…”.

Ejemplo:

Entero *apuntador, j;

Esta sentencia declara que apuntador apunta a un valor u objeto de tipo entero. Al declarar una variable como puntero.

Los punteros se deben inicializar a 0, NULL o a una dirección, al declararlos o bien utilizando el operador de asignación.

Ejemplo:

entero *p, k;
  p = &k;

 

Cualquier variable utilizada en programación de computadores tiene asociada una dirección de memoria, así por ejemplo, las siguientes líneas de pseudocódigo dan como salida la dirección de k.

int k

k = 50

Escriba(“La dirección de memoria es “, &k)

Fin

 

 

Veamos otro ejemplo codificado en C++

En el ejemplo anterior, se leen dos números enteros, se calcula su resto. Se muestran por pantalla los números leídos, el resto y la correspondiente posición de memoria para cada variable, A continuación, una captura de pantalla del código ejecutado.

Como puede observarse, declaramos tres variables llamadas num1, num2 y resto que contiene un valor leído o asignado, para mostrarlo en pantalla solo tenemos que hacer como lo hemos hecho desde siempre, imprimiendo la variable. Ahora, si al principio de la variable agregamos el operador de dirección, hará la acción de convertirse en punteros y por eso vemos que la ejecución del programa nos está mostrando en pantalla el valor de las variables con la correspondiente posición de memoria de cada uno por haber agregado el operador &.

 

Los apuntadores son usados principalmente para crear estructuras de datos, y el uso más común es para el ahorro de memoria gracias a que el tipo de memoria usada es dinámica. La memoria dinámica permite que se expanda la capacidad de datos o se eliminen y se usen los necesarios. Para esta función se utiliza los operadores new y delete.

 

New se encarga de reservar el número de bytes necesarios para poder declarar y delete se coloca al final del programa, es el que borra el bloque de bytes reservado al principio para así en conjunto con new utilizar sólo la cantidad de memoria necesaria. Veamos el siguiente ejemplo.

 

Ejemplo:

Se desea obtener el peso promedio de los estudiantes de una escuela, para ello se requiere almacenar en un vector peso los datos obtenidos. Se debe mostrar por pantalla los pesos almacenados y el peso promedio de toda la población estudiada.

Solución:

Algoritmo

Inicio

   Int  num=0, *peso=NULL, sumatoria=0, prom = 0

   Escriba(“Teclee el número de estudiantes: “)

   Lea(num)

   Peso = new int[num]

   Para(int i = 0; i < num; i++)

      Escriba(Ingrese el peso: )

      Leer(peso[i])

      Sumatoria = sumatoria + peso[i]

   Fin-para

   prom = sumatoria / num

   Escriba(Los pesos registrados son: )

   Para(int i = 0; i < num; i++)

      Escriba(peso[i]

   Fin-para

   Escriba(“El promedio es: “, prom)

   Delete []peso

Fin

 

Código C++

Ejemplo:

A partir de una matriz m x n leída por teclado escribir la transpuesta n x m. Se deben leer m y n para generar un arreglo dinámico.

Algoritmo

Inicio

    int m, n, **arreglo = NULL;

    Escriba(“Teclee el número de filas y de columnas ")

    Leer(m, n)

    arreglo = new int* [m];

 

    para(int i = 0; i < m; i++)

        arreglo[i] = new int[n];

    fin-para

    Escriba("Digite " ,m * n, " enteros.\n")

 

    para(int i = 0; i < m; i++)

        para(int j = 0; j < n; j++)

            Leer(arreglo[i][j])

        fin-para

    fin-para

 

    Escriba("Matriz original")

    para(int i = 0; i < m; i++)

        para (int j = 0; j < n; j++)

            Escriba(arreglo[i][j])

        fin-para

    fin-para

   

    Escriba("Matriz transpuesta")

    para(int i = 0; i < n; i++)

        para(int j = 0; j < m; j++)

            Escriba(arreglo[j][i])

        fin-para

    fin-para

 

    delete[]arreglo

Fin

 

 

Código C++

Ejemplo:

 

 Se pide escribir el pseudocódigo de un programa que calcule el producto de dos matrices Mat1 y Mat2 con asignación dinámica de memoria: Se debe pedir por teclado las dimensiones de la matriz Mat1 (filas y columnas) y las columnas de la matriz Mat2, ya que las filas tienen que ser igual a las columnas de Mat1 para poder ser multiplicadas.

 

La salida por consola debe mostrar las dimensiones de la matriz resultante y los datos de la matriz resultante.

Algoritmo

Inicio

  int filas, cols1,cols2,

  **Mat1 = NULL, **Mat2 = NULL, **MatP = NULL

  Escriba(“Número de filas y columnas de la matriz 1: ")

 

  Leer(filas, cols1)

  Mat1 = new int* [filas], Mat2 = new int* [cols1],

  MatP = new int* [filas]

 

  para(int i = 0; i < filas; i++)

      Mat1[i] = new int[cols1]

  fin-para

 

  Escriba(“El número de columnas de la matriz 2 “)

  Leer(cols2)

 

  para(int i = 0; i < cols1; i++)

      Mat2[i] = new int[cols2]

  fin-para

  para(int i = 0; i < filas; i++)

      MatP[i] = new int[cols2]

  fin-para

 

  Escriba("Digite " ,filas * cols1, " enteros para la matriz 1)

 

  para(int i = 0; i < filas; i++)

      para(int j = 0; j < cols1; j++)

          Leer(Mat1[i][j])

      fin-para

  fin-para

 

  Escriba("Digite " ,cols1 * cols2, " enteros para la matriz 2)

 

  para(int i = 0; i < cols1; i++)

      para(int j = 0; j < cols2; j++)

          Leer(Mat2[i][j])

      fin-para

  fin-para

   

  Escriba("Dimesiones de matriz producto: “, filas * cols2)

   

  Escriba("Matriz resultante")

  para(int i = 0; i < filas; i++)

      para(int j = 0; j < cols2; j++)

          Escriba(MatP[i][j]=Mat1[i][j]*Mat2[i][j]+    

                  Mat1[i][j+1]* Mat2[i+1][j]+

                  Mat1[i][j+2]* Mat2[i+2][j])

      fin-para

  fin-para

 

  delete[]Mat1

  delete[]Mat2

  delete[]MatP

Fin

 

Código C++