Sie sind auf Seite 1von 22

Punteros

Todo lo que deberías el de MP supiese explicar.

Por: Adrià Ciurana Lanau

Punteros

1.-¿Qué son? 2.-¿Qué nos permiten? 3.-Paso por referencia 4.-Creación de registros 5.-Listas dinámicas 5.1.-FIFO (First In First Out, o cola) -¿Qué es? -Recorrer una Cola -Añadir Elemento -Eliminar Elemento 5.2.- LIFO (Last In Fist Out, o pila) -¿Qué es? -Recorrer una pila -Añadir Elemento -Eliminar Elemento 6.-Diferencias para de Listas o pilas

1.-¿Qué Son?

Los punteros son variables que en vez de almacenar datos directamente, almacenan direcciones de memoria.

Declaración en Pseudocódigo:

puntero: punter a TIPO

Ej: p: punter a tNode Declaración en C:

TIPO *puntero;

Ej: struct tNode *p;

Cuando decimos que un puntero esta apuntando a algo, se refiere a que ese puntero guarda la dirección de memoria de ese elemento.

Para entenderlo de forma mas sencilla vamos ha hacer un ejemplo.

#99

Memoria 10 variable
Memoria
10
variable

Puntero

Aquí vemos como un puntero apunta a una variable entera, pero realmente cuando decimos que una cosa apunta a otra, nos estamos refiriendo a que almacena su dirección en la memoria.

Por lo que el valor realmente del puntero es Puntero=#99 (direccionamiento indirecto).

Obtener dirección en la memoria de un elemento:

Cuando tenemos una variable (de cualquier tipo), simplemente si queremos saber su dirección en la memoria, debemos introducir “&” delante de la misma variable.

Entonces si hago &variable, esto me devuelve la posición en memoria de este elemento y no su contenido.

Ej: &variable nos devuelve #99

Interpretación del contenido de un elemento como un direccionamiento indirecto:

Primero y antes de todo, definiremos que es un direccionamiento indirecto, pues simplemente se trata de interpretar que lo que guarda una variable es una dirección de memoria.

Ej: variable2=&variable /*variable2 ahora valdria #99*/ *variable2=variable /*Ahora interpretaríamos que aquello que guardaba la variable2, es una dirección de memoria y que queremos ver el contenido de dicha dirección de memoria*/

2.-¿Qué nos permiten?

Con esa relación entre un puntero y una variable, podemos realizar un sinfín de operaciones, por ejemplo modificar valores en un procedimiento. (paso por referencia). O crear un seguido de nodos que nos permitirán avanzar nodo a nodo, para así crear listas dinámicas.

3.-Paso por referencia

El paso por referencia técnicamente en pseudocódigo se declara de la siguiente forma:

Procedimiento proceso(var variable)

Con eso permitimos que los cambios en que la variable se modifique dentro de la función o procedimiento, después de haber salido de ella misma, sigan aplicados. Es decir que después de haber salido de la función aquella variable no valdrá lo mismo que cuando entro.

En pseucódigo, no tiene ninguna relación con punteros pero en cambio en C, no existe ninguna forma de indicar que esa variable todos los cambios que se le apliquen se sigan aplicando fuera, por lo que se hace una especie de parche.

En vez de pasar la propia variable, se pasa su dirección en memoria &variable, y luego se asigna un puntero que apunta a esa variable TIPO *puntero.

Esto se hace de la siguiente forma:

Void proceso(int *variable2)

*variable2=….

Con eso indicamos que pasaremos una dirección de memoria y el puntero *variable deberá apuntarla.

Cuando queramos utilizar dicha función:

proceso(&variable);

Pasaremos la dirección de memoria de la variable.

Con lo que realmente hacemos esto:

Pasamos &variable que vale #99, indicamos que un puntero apunte a #99, y para modificar los datos indicamos que “variable2” guarda una dirección de memoria y que nos lo interprete como tal *variable2 (direccionamiento indirecto).

4.-Creación de registros

El uso de registros es constante para crear listas dinámicas en punteros, por lo que antes de entrar en tema, explicaremos que son los registros.

Un registro no es más que una variable con muchas subvariables, por decirlo de alguna manera es como un contenedor que engloba un conjunto de variables.

En pseudocódigo se indica de la siguiente forma:

Alumno =registro ( nombre: cadena Id: enter Email: cadena

)

Y en C de la siguiente manera:

Struct Alumno { Char nombre; Int id; Char email;

};

Pero aún no vemos que posible relación puede tener un registro con las listas dinámicas.

Pues es simplemente que en un registro podemos poner un puntero a un mismo registro.

Pseudocódigo:

Alumno =registro ( nombre: cadena Id: enter Email: cadena

Siguiente: punter a Alumno

)

En C:

Struct Alumno { Char nombre; Int id; Char email;

Struct Alumno *siguiente;

};

Por lo que este registro tiene un puntero llamado siguiente que apuntará a otro registro del mismo tipo (tipo alumnos).

5.-Listas Dinámicas

Las listas dinámicas son aquellas listas en que desconoces el número de elementos que puedes incluir como máximo en ella, es decir desconoces el número de elementos que tendrás.

Por lo que para ello es necesario utilizar punteros (¿Si, chicos una putada no?).

Tipos de listas dinámicas:

En el fondo clasificar los tipos de listas que hay es algo útil pero no quiere decir que solo hayan dos tipos, al ser realizado con punteros podemos hacer virguerías como árboles, grafos, listas que se añaden como pilas y se borran como colas, etc. Pero de hecho las que más se utilizan se resumen a dos tipos:

-Colas (FIFO)

-Pilas (LIFO)

5.1.-FIFO

-¿Qué son?

Las FIFO o colas, son aquellas en que el primer elemento en entrar es el primero en salir, eso lo podemos asociar a cualquier acción en la vida normal como ir a comprar unas entradas, hacer cola en la discoteca.

Para crear una cola dinámica utilizamos los siguientes registros:

En Pseudocódigo:

Nodo= registro( numero: entero Siguiente: punter a Nodo

)

Cola = registro( primero: punter a Nodo

)

En C:

Struct Nodo{ Int Numero; Struct Nodo *Siguiente; }:

Struct Cola{ Struct Nodo *Primero; };

Podemos apreciar que realmente estamos usando dos punteros, el “siguiente” unirá todos los nodos entre si para poder recorrer su información. Y el primero indicará el punto de inicio de la cola. Es punto de fin es tan fácil como detectar que el siguiente de un nodo no existe.

-¿Cómo recorrerlas?

Para recorrer toda una cola necesitamos simplemente un puntero auxiliar para indicar en que punto de la cola estamos.

Para ello podemos utilizar el puntero “actual” y el “anterior”.

Podemos distinguir dos fines para recorrer una cola:

-Añadir un elemento. -Eliminar un elemento.

PD: En este caso es lo mismo pero si hacemos funcionamientos en que se añada un elemento como una pila y se borre como una cola es bien distinto.

Cuando queremos recorrer una lista hacemos lo siguiente:

Pseudocódigo:

Anterior,Actual: punter a Nodo

Anterior NUL Actual Cola.primero /*Nos posicionamos en el inicio de la lista*/ Mientras(Actual!=NUL) /*Con esto indicamos que la lista no es nula*/

/*Operaciones que queremos realizar*/

Anterior Actual Actual Actual Siguiente Fimientras

En C:

Struct Nodo *Anterior,*Actual;

Anterior=NULL;

Actual=Cola.primero;

While(Actual!=NULL){

/*Operaciones que queremos realizar*/

Anterior=Actual;

Actual=Actual->Siguiente;

}

-Añadir elemento en una Cola

Para añadir un elemento a una cola, debemos distinguir diferentes casos:

1.-Único elemento de la cola. 2.-Primer elemento de la cola. 3.-Elemento entre el medio de la lista. 4.-Último de la lista. 5.-Agrupando Casos

Utilizaremos las operaciones assignar(puntero) (asigna a puntero NUL si no hay memoria disponible), alliberar(puntero) para crear elementos en la memoria dinámica donde apuntará el puntero.

Para añadir elementos a una cola utilizaremos el anterior siempre, ya que eso nos indicará siempre que caso es.

1.-Único elemento de la cola:

Eso nos indica que esta cola antes es nula, que no existe ningún valor anteriormente. Por lo que anteriormente no valía nada (NUL) y el primero tampoco.

Entonces si la cola es nula, el anterior también lo será:

Pseudocodigo:

P: punter a Nodo

Assignar(p)

p num

p Siguiente=NUL /*Con esto evitamos que nos recorra más*/ Si(p!=NUL) /*Comprovamos que nos ha asignado memoria*/ Si(Anterior=NUL AND Cola.primero=NUL) /*Comprovamos anterior es nulo*/ Cola.primero p

numero

Fisi

Fisi

En C:

Struct Nodo *p;

p=(Struct Nodo*)malloc(sizeof(Struct Nodo)); /*Simplemente dice que guarde una parte de la memoria dinamica del tamaño de struct nodo, y que p apunte a ella*/

p num= numero;

p

Siguiente=NULL;

if(p!=NUL){

if(anterior==NULL && Cola.primero==NULL){ Cola.primero=p

}

}

Y así simplemente asignamos p como el primer elemento de la cola.

2.-Primer elemento de la cola:

Si queremos insertar un elemento en una cola que contiene datos, pero queremos hacerlo en la primera posición. Sabemos que Anterior=NUL, pero que la Cola.primero no lo será.

Pseudocodigo:

P: punter a Nodo

Assignar(p) p num numero

p

Siguiente NUL Si(p!=NUL) /*Comprovamos que nos ha asignado memoria*/

Si(Anterior=NUL AND Cola.primero!=NUL) /*Comprovamos anterior es nulo*/

En C:

Fisi

Fisi

Struct Nodo *p;

p Siguiente Cola.primero p

Cola.primero

p=(Struct Nodo*)malloc(sizeof(Struct Nodo)); /*Simplemente dice que guarde una parte de la memoria dinamica del tamaño de struct nodo, y que p apunte a ella*/

p num= numero;

p

Siguiente NULL; if(p!=NUL){ if(anterior==NULL && Cola.primero!=NULL){

p Siguiente=Cola.primero Cola.primero=p

}

}

Lo que estamos haciendo es lo siguiente: Primero asignamos p, luego indicamos

que el siguiente del mismo es el elemento que actualmente es el primero de la cola,

y luego indicamos que ahora él es el primero de la cola.

3.-Elemento entre el medio de la lista:

Si queremos insertar un elemento en el medio de la cola, sabemos que el Anterior!=NUL, y el Anterior Siguiente (equivalente a Actual)!=NUL

Pseudocodigo:

P: punter a Nodo

Assignar(p)

p

num numero

p

Siguiente NUL Si(p!=NUL) /*Comprovamos que nos ha asignado memoria*/ Si(Anterior!=NUL AND Anterior Siguiente!=NUL) /*Comprovamos anterior no es nulo*/ p Siguiente Anterior Siguiente Anterior Siguiente p

En C:

Fisi

Fisi

Struct Nodo *p;

p=(Struct Nodo*)malloc(sizeof(Struct Nodo)); /*Simplemente dice que guarde una parte de la memoria dinamica del tamaño de struct nodo, y que p apunte a ella*/

p

num= numero;

p

Siguiente=NULL;

if(p!=NUL){

if(anterior!=NULL && Anterior Siguiente!=NULL){

p Siguiente=Anterior Siguiente Anterior Siguiente=p

}

}

4.-Último de la lista:

Si queremos insertar un elemento al final de la cola sabemos que el Anterior!=NUL

y el Anterior Siguiente=NUL (equivalente a Actual)

Pseudocodigo:

P: punter a Nodo

Assignar(p)

p num numero Si(p!=NUL) /*Comprovamos que nos ha asignado memoria*/ Si(Anterior!=NUL AND Anterior Siguiente=NUL) /*Comprovamos anterior no es nulo*/ Anterior Siguiente p

En C:

Fisi

Fisi

Struct Nodo *p;

p=(Struct Nodo*)malloc(sizeof(Struct Nodo)); /*Simplemente dice que guarde una parte de la memoria dinamica del tamaño de struct nodo, y que p apunte a ella*/

p num= numero if(p!=NUL){

if(anterior!=NULL && Anterior Siguiente=NULL){ Anterior Siguiente=p

}

}

De modo que anterior Siguiente será p.

5.-Agrupando Casos:

Podemos agrupar los casos para que sea mas compacto el añadir.

Pseudocodigo:

P: punter a Nodo

Assignar(p)

p

num numero

p

Siguiente NUL

Si(p!=NUL)

Si(Anterior=NUL) /*Casos 1 y 2*/

p

Siguiente

Cola.primero

Cola.primero

p

Fisi

En C:

Sino /*Casos 3 y 4*/

p Siguiente

Anterior Siguiente p

Anterior Siguiente

Fisi

Struct Nodo *p; p=(Struct Nodo*)malloc(sizeof(Struct Nodo));

p

num=numero;

p

Siguiente=NULL;

if(p!=NULL){ If(Anterior==NULL){

p Siguiente=Cola.primero Cola.primero=p

} else {

 

p

Siguiente=Anterior Siguiente:

Anterior Siguiente=p;

}

}

El caso 1 y 2, técnicamente son iguales, porque si es el caso 1, cola.primero será nulo y no cambiaremos nada, y si es el caso 2, cola.primero será el primero de la cola.

El caso 3 y 4, más de lo mismo, si se trata del caso 4 Anterior Siguiente no valdrá nada, por lo que no cambiaremos nada, y si es el caso 3, Anterior Siguiente si valdrá algo.

-Eliminar elemento en una Cola:

Bueno, antes hemos visto como añadir un elemento a una cola, ahora veremos el otro caso como eliminarlo.

Para eliminar un elemento a una cola, debemos distinguir diferentes casos:

1.-Único elemento de la cola. 2.-Primer elemento de la cola. 3.-Elemento entre el medio de la lista. 4.-Último de la lista. 5.-Agrupando Casos

1.-Único elemento de la cola:

Para eliminar el único elemento de una cola sabemos que el Anterior=NUL y el Anterior Siguiente (equivalente a Actual)=NUL, ya que nos pondremos en la cabeza de la cola. En este caso usaremos P como el puntero al elemento a eliminar en vez de usarlo para el elemento a añadir.

Pseudocódigo:

P: punter a Nodo

Si(Anterior=NUL AND Cola.primero Siguiente=NUL)

p Cola.primero

Cola.primero NUL

Fisi

Alliberar(p);

En C:

Struct Nodo *p;

If(Anterior==NULL){

P=Cola.primero

Cola.primero=NUL

}

Free(p);

2.-Primer elemento de la cola:

Para eliminar el primer elemento de una cola sabemos que el Anterior=NUL y que el Anterior Siguiente (equivalente a Actual) !=NUL.

Pseudocódigo:

P: punter a Nodo

Si(Anterior=NUL AND Cola.primero Siguiente=NUL)

p Cola.primero

Cola.primero p Siguiente /*Equivalente a

Cola.primero

Cola.primero Siguiente*/

Fisi

Alliberar(p);

En C:

Struct Nodo *p;

If(Anterior==NULL && Cola.primero Siguiente!=NULL){ P=Cola.primero; Cola.primero=NUL;

}

Free(p);

3.-Elemento entre el medio de la lista:

Para eliminar el elemento que esta entre medio de una cola sabemos que el Anterior!=NUL y que el Anterior Siguiente(equivalente a Actual)!=NUL

P: punter a Nodo

Si(Anterior!=NUL AND Anterior Siguiente!=NUL)

p Anterior Siguiente

Anterior Siguiente

Fisi

Alliberar(p);

En C:

Struct Nodo *p;

p Siguiente

If(Anterior!=NULL && Anterior Siguiente!=NULL){ P=Anterior Siguiente; Anterior Siguiente=p Siguiente;

}

Free(p);

4.-Ultimo elemento de la lista:

Para eliminar el elemento que esta al final de una cola sabemos que el Anterior!=NUL y que el Anterior Siguiente (equivalente a Actual)=NUL.

P: punter a Nodo

Si(Anterior!=NUL AND Anterior Siguiente=NUL)

p Anterior Siguiente

Anterior Siguiente

Fisi

Alliberar(p);

En C:

Struct Nodo *p;

NUL

If(Anterior!=NULL && Anterior Siguiente==NULL){ P=Anterior Siguiente; Anterior Siguiente=NULL;

}

Free(p);

5.-Agrupando Casos:

Podemos agrupar los casos de eliminar de la siguiente forma:

P: punter a Nodo

Si(Anterior==NUL)

P Cola.primero

Cola.primero p Siguiente

Sino

P Anterior Siguiente

Anterior Siguiente p Siguiente

Fisi

Alliberar(p);

En C:

Struct Nodo *p;

If(Anterior!=NULL){ P=Cola.primero; Cola.primero= p Siguiente;

} else {

P=Anterior Siguiente; Anterior Siguiente=p Siguiente

}

Free(p);

5.1.-LIFO

-¿Qué son?

Las LIFO o pilas, son aquellas en que el primer elemento en entrar es el ultimo en salir, eso lo podemos asociar a cualquier acción en la vida normal como ir a apelotonar libros, platos, etc.

Para crear una pila dinámica utilizamos los siguientes registros:

En Pseudocódigo:

Nodo= registro( numero: entero Siguiente: punter a Nodo

)

Pila = registro(top: punter a Nodo

)

En C:

Struct Nodo{ Int Numero; Struct Nodo *Siguiente; }:

Struct Pila{ Struct Nodo *Top; };

Podemos apreciar que realmente estamos usando dos punteros, el “siguiente” unirá todos los nodos entre si para poder recorrer su información. Y el top indicará el punto de arriba del todo de la pila. Es punto de fin es tan fácil como detectar que el siguiente de un nodo no existe.

-Recorrer una Pila:

Para recorrer una pila, hacemos exactamente lo mismo que cuando recorres una cola.

-Añadir Elemento a pila:

En este caso de las pilas solo hay un caso es lo que se le llama normalmente push de pila.

Cuando añades un elemento a la pila simplemente subes el top al nuevo elemento.

Pseudocódigo:

P: punter a Nodo Asignar(p);

p

num numero

p

Siguiente=NULL;

Si(p!=NUL)

P Siguiente Pila.Top Pila.Top p

Fisi

En C:

Struct Nodo *p;

P= (Struct Nodo*)malloc(sizeof(Struct Nodo)); If(p!=NULL){

P Siguiente=Pila.Top; Pila.Top= p;

}

-Eliminar Elemento a pila:

En este caso de las pilas para eliminar un elemento también solo hay un caso que se le llama normalmente pop de pila.

Cuando eliminar un elemento de la pila bajas el top.

Pseudocódigo:

P: punter a Nodo Si(Pila.Top!=NUL) P Pila.Top Pila.Top p Siguiente

Fisi

Alliberar(p)

En C:

Struct Nodo *p;

P= (Struct Nodo*)malloc(sizeof(Struct Nodo)); If(Pila.Top!=NULL){ P=Pila.Top; Pila.Top= p Siguiente;

}

Free(p);

6.-Diferencias entre una Cola y una Pila:

1.- Los enlaces entre los nodos de la pila son de arriba abajo y los de la Cola de derecha a izquierda.

2.- El top se situa en el elemento final de la pila y en cambio en la cola el primero se situa en el primer elemento de la cola.

Representación grafica:

-Pila:

pila y en cambio en la cola el primero se situa en el primer elemento de

-Cola:

pila y en cambio en la cola el primero se situa en el primer elemento de