REPÚBLICA BOLIVARIANA DE VENEZUELA MINISTERIO DEL PODER POPULAR PARA LA DEFENSA UNIVERSIDAD NACIONAL EXPERIMENTAL DE LA FUERZA ARMADA NÚCLEO FALCÓN - EXTENSIÓN PUNTO FIJO Apuntadores / Estructura de datos lineales Docente: Licda. Marialix Quintero Punto Fijo, Mayo de 2011
Una de las aplicaciones más interesantes y potentes de la memoria dinámica y los punteros son las estructuras dinámicas de datos. Las estructuras básicas disponibles en C y C++ tienen una importante limitación: no pueden cambiar de tamaño durante la ejecución. Los arreglos están compuestos por un determinado número de elementos, número que se decide en la fase de diseño, antes de que el programa ejecutable sea creado. En muchas ocasiones se necesitan estructuras que puedan cambiar de tamaño durante la ejecución del programa. Por supuesto, podemos hacer 'arrays' dinámicos, pero una vez creados, tu tamaño también será fijo, y para hacer que crezcan o diminuyan de tamaño, deberemos reconstruirlas desde el principio, por este motivo los arrays no hacen un uso eficiente de la memoria.
OBJETIVOS Entender la eficacia del manejo de la memoria dinámica a través del uso de apuntadores Lograr un uso eficiente de las estructuras de datos lineales.
Definición. Ventajas y desventajas. Declaración / Inicialización Punteros NULL y void Punteros o apuntadores
Punteros o apuntadores (Direcciones en memoria) El proceso de asignación dinámica de memoria permite crear y destruir variables en tiempo de ejecución (variables dinámicas). Cuando una variable se declara, se asocian tres atributos fundamentales con la misma: su  nombre,  su  tipo  y su  dirección  en memoria. Ejemplo: int n;  / * asocia al nombre n, el tipo int y la dirección de alguna posición de memoria donde se almacena el valor de n* / Al valor de una variable se accede por medio de su nombre. Por ejemplo, se puede imprimir el valor de n con la sentencia:  cout<<n;   A la dirección de la variable se accede por medio del  operador de dirección  &.  Por ejemplo, se puede imprimir la dirección de n con la sentencia:  cout<<&n; Ox4f f fd34 n int
Ejemplo: Hacer un programa muestre por pantalla el valor y la dirección de una variable x de tipo entero. #include <stdio.h> void main() { int n = 75; cout<<”el valor de n es: ”<<n;  cout<<”la dirección de memoria de n es: ”<<&n; }  Ojo: la dirección viene dada en hexadecimal Punteros o apuntadores (Direcciones en memoria)
L as variables vistas hasta este momento contienen valores de datos, por el contrario las variables punteros contienen valores que son direcciones de memoria donde se almacenan datos. En resumen, un puntero es una variable que contiene una dirección de memoria, y utilizando punteros su programa puede realizar muchas tareas que no sería posible utilizando tipos de datos estándar. Punteros o apuntadores (Definición) Puntero= variable  dirección de memoria  dirección de memoria de otra variable = Puntero a punta a otra variable
Cuando se telefonea a una persona, se utiliza un puntero (el número de teléfono que se marca).  Punteros o apuntadores (Ejemplos) Cuando se envía una carta por correo, su información se entrega basada en un puntero que es la dirección de esa carta. Así   pues, una dirección de correos y un número de teléfono tienen en común que ambos indican dónde encontrar algo.
Punteros o apuntadores (Ventajas y desventajas) Los punteros tienen una gran utilidad, pues permiten una programación eficaz a nivel de máquina cuando se maneja la memoria del ordenador. Permiten realizar operaciones de asignación dinámica de memoria. Permiten efectuar operaciones con estructuras de datos dinámicas. Ventajas Los punteros deben usarse con precaución, ya que pueden provocar fallos en el programa difíciles de localizar, puede ser por asignación incorrecta de dirección.   Desventajas
Los tipos de datos tienen que corresponderse es decir (declaración de variable de tipo de dato).  Los punteros se enlazan a tipos de datos específicos, de modo que C verificará si se asigna la dirección de un tipo de dato al tipo correcto de puntero.  Así,  por ejemplo, si se define un puntero a float, no  se  le puede asignar la dirección de un carácter o un entero.  Por ejemplo, este segmento de código no  funcionará: Ejemplo: float *fp; char c; fp = &c; / * no es válido * / Existen dos operadores especiales de punteros:  & y *.  El operador de dirección  (&)  devuelve la dirección de memoria de su operando. El operador de indirección  (*)  devuelve el contenido de la dirección apuntada por el operando. Punteros o apuntadores (Ventajas y desventajas)
Inicialización Ejemplos de Asignación estática de memoria void main(){ int a; int* b; b = &a;         //El puntero 'b' apunta a 'a'. } Punteros o apuntadores (Declaración e inicialización) Declaración tipo_de_dato *nombre_var_puntero ej: int *punt; float *nuevo;
Existen dos tipos de punteros especiales muy utilizados en el tratamiento de sus programas: los punteros void y null (nulo). Un  puntero nulo  no apunta a ninguna parte -dato válido- en particular, es decir, «un puntero nulo no direcciona ningún dato válido en memoria». Un puntero nulo se utiliza para proporcionar a un programa un medio de conocer cuando una variable puntero no direcciona a un dato válido. Para declarar un puntero nulo se utiliza la macro NULL, definida en los archivos de cabecera STDEF . H, STDIO. H, STDLIB. H y STRING. H. Se debe incluir uno o más de estos archivos de cabecera antes de que se pueda utilizar la macro NULL. Ejemplos: char *p = NULL; Estático nuevo->sig=NULL; Dinámico En C se puede declarar un puntero de modo que apunte a cualquier tipo de dato, es decir, no se asigna a un tipo de dato específico.  En C se puede declarar un puntero de modo que apunte a cualquier tipo de dato, es decir, no se asigna a un tipo de dato específico. El método es declarar el puntero como  un puntero void *, denominado puntero genérico.  Punteros o apuntadores (Punteros Null y void)
Definición. Tipos de listas. Operaciones con listas. Listas lineales
Las estructuras dinámicas nos permiten crear estructuras de datos que se adapten a las necesidades reales a las que suelen enfrentarse nuestros programas. Pero no sólo eso, también nos permitirá crear estructuras de datos muy flexibles, ya sea en cuanto al orden, la estructura interna o las relaciones entre los elementos que las componen.  Las estructuras de datos están compuestas de otras pequeñas estructuras a las que llamaremos nodos o elementos, que agrupan los datos con los que trabajará nuestro programa y además uno o más punteros autoreferenciales, es decir, punteros a objetos del mismo tipo nodo.  Una estructura básica de un nodo para crear listas de datos seria: struct nodo { int dato;  struct nodo *sig; }; Listas lineales (Definición)
Tipos de listas Simples Circulares Doble El último elemento tiene que apuntar NULL. En las listas hay un nodo especial que es el primero ya que guarda el inicio de la lista y a través de ese nodo se puede recorrer la lista. Si el nodo inicial es NULL indica que la lista está vacia.
Es una colección o secuencia de elementos dispuestos uno detrás de otro, en la que cada elemento se conecta al siguiente elemento por un «enlace» o «puntero».  La idea básica consiste en construir una lista cuyos elementos llamados  nodos  se componen de dos partes o  campos:  la primera parte o campo contiene  la información  y la segunda parte el puntero que guarda  la dirección de memoria del siguiente nodo  de la lista o valdrá NULL si es el último elemento.  En las listas abiertas existe un nodo especial: el primero. Normalmente diremos que nuestra lista es un puntero a ese primer nodo y llamaremos a ese nodo la cabeza de la lista. Eso es porque mediante ese único puntero podemos acceder a toda la lista.  Cuando el puntero que usamos para acceder a la lista vale NULL, diremos que la lista está vacía.  “LAS LISTAS SON ORDENADAS” Lista simple o abierta
Declaración: struct nodo{ int dato; struct nodo *siguiente; } *nuevo,*aux,*ant, *inicio=NULL; Lista simple o abierta (Operaciones con listas) Inicialización:   inicio=NULL; Insertar Caso 1: Lista Vacía El proceso es muy simple, bastará con comprobar si la lista==NULL: nuevo->siguiente apunte a NULL.  Lista apunte a nuevo.  Código if (inicio==NULL){ nuevo=new nodo; nuevo->dato=elem; nuevo->sig=NULL; inicio=nuevo; } 10  NULL
Caso 2: Insertar un elemento en la primera posición de la lista (menor que el 1er elemento) El proceso sigue siendo muy sencillo: Hacemos que nodo->siguiente apunte a Lista.  Hacemos que Lista apunte a nodo.  Lista simple o abierta (Operaciones con listas) Código: else if (elem<=inicio->dato){ nuevo=new nodo; nuevo->dato=elem; nuevo->sig=inicio; inicio=nuevo; } 10  NULL 5  sig 10  50
Caso 3: Insertar un elemento después de un nodo cualquiera de la lista Procedimiento Recorrer la lista e ir guardando el anterior cuando se encuentre la posición correcta, el anterior debe apuntar al nuevo nodo y el nuevo->siguiente a la posición siguiente del anterior. Lista simple o abierta (Operaciones con listas) else {  aux=inicio; while (aux!=NULL){ if (elem<aux->dato) break; ant=aux; aux=aux->sig; } nuevo=new nodo; nuevo->dato=elem; ant->sig=nuevo; nuevo->sig=aux; } 10  NULL 5  sig Aux=10-50 Elem=7 Ant=10 7  NULL 10  50  20  5  sig 10  7  sig 20  10  NULL 50
Recorrer / Mostrar void mostrar() { nodo *aux; aux=inicio; while(aux!=NULL){ cout<<&quot;\t&quot;<<aux->dato<<&quot;\n&quot;; aux=aux->sig;} aux=lista;} Lista simple o abierta (Operaciones con listas) 5  sig 10  7  sig 20  10  NULL 50
Buscar / Eliminar:  Se debe recorrer la lista buscando el elemento a borrar, tomando en cuenta su posición en la lista: si es el primer elemento, el último o esta en el medio. void eliminar(int elem) { aux=inicio; while (aux!=NULL){   if (elem==aux->dato) break; ant=aux; aux=aux->sig; }//while if(aux==NULL) cout<<&quot;elemento no encontrado\n&quot;; else{ if (aux==inicio)//primer elemento inicio=aux->sig; else if (aux->sig==NULL)//ultimo ant->sig=NULL; else ant->sig=aux->sig; delete(aux);} } Lista simple o abierta (Operaciones con listas) 5  sig 10  7  sig 20  10  NULL 50  Aux=10-20 Elem=7 Ant=10
Cuerpo del programa Librería:  #include <iostream.h> void main(){ int op; while (op<4) {  cout<<&quot;Listas Dinamicas - Menu Principal\n\n&quot;;   cout<<&quot;1.Insertar\n&quot;;   cout<<&quot;2.Eliminar\n&quot;;   cout<<&quot;3.Mostrar\n&quot;;   cout<<”4.Salir\n\n&quot;;   cout<<&quot;Seleccione una opcion: &quot;;  cin>>op;   int dat;     switch (op){   case 1: { cout<<&quot;Dato: &quot;;   cin>>dat;   insertar(dat);   break;  }   case 2:  { cout<<&quot;Dato: &quot;;   cin>>dat; eliminar(dat);   break;}   case 3:{   mostrar();   break; }   } } } Lista simple o abierta (Operaciones con listas)
Ejercicios propuestos de listas simple Escribir una función que imprima el número de nodos de una lista simple. Escribir una función que elimine el nodo que ocupa la posición i (dada por el usuario) de una lista simple, siendo el nodo inicio que ocupa la posición n°1. Escribir una función que no permita insertar datos no repetidos.
Declaración: struct nodo{ int elem; nodo *sig; nodo *ant; }*inicio=NULL, *fin=NULL, *aux, *nuevo; Lista doble (Operaciones con listas) 5  sig 10   ant void mostrar(){ aux=inicio; if (aux==NULL) cout<<&quot;\nLista Vacia&quot;; while(aux!=NULL){ cout<<aux->elem<<&quot;\t&quot;; aux=aux->sig; } } Inicio 4  Sig 10 Ant Null 5  Sig 80 Ant 20 20   8  Sig null Ant 80 10   50   8  Sig 50 Ant 10 80
void insertar(){ int dato; nuevo=new nodo; cout<<&quot;Ingrese numero: &quot;; cin>>dato; nuevo->elem=dato; if (inicio==NULL){//lista vacia nuevo->sig=NULL; nuevo->ant=NULL; inicio=nuevo; fin=nuevo; } else if(dato<inicio->elem){//inserto al inicio nuevo->sig=inicio; nuevo->ant=NULL; inicio->ant=nuevo; inicio=nuevo; } else if(dato>fin->elem){//inserto por el final nuevo->ant=fin; nuevo->sig=NULL; fin->sig=nuevo; fin=nuevo; } else{//se recorre la lista aux=inicio; while(aux!=NULL){ if(dato<aux->elem) break; aux=aux->sig; }//while //se enlaza con el siguiente nuevo->sig=aux; nuevo->ant=aux->ant; aux->ant->sig=nuevo; aux->ant=nuevo; } } 5  sig 10   ant 4  Sig 10 20   Ant Null 5  Sig null 10   Ant 20 Inicio Inicio Nuevo-inicio Inicio Inicio Null Nuevo 4  Sig 10 Ant Null 5  Sig 50 Ant 20 20   8  Sig null Ant 10 10   50   6  sig 80   ant Null Inicio Inicio 4  Sig 10 Ant Null 5  Sig 80 Ant 20 20   8  Sig null Ant 80 10   50   8  Sig 50 Ant 10 80   Nuevo
void eliminar(){ int dato_eli; cout<<&quot;Ingrese dato a eliminar: &quot;; cin>>dato_eli; aux=inicio; while(aux!=NULL){ if(dato_eli==aux->elem) break; aux=aux->sig; } //se evaluan 4 casos if(aux==NULL){//no encontrado cout<<&quot;elemento no encontrado\n&quot;; } else if(aux==inicio){//borra el 1er nodo   if((aux->sig==NULL) &&(aux->ant==NULL) ){ inicio=NULL; fin=NULL;} else{ inicio=inicio->sig; inicio->ant=NULL;} } else if (aux==fin){//borra el ultimo nodo if((aux->sig==NULL) &&(aux->ant==NULL) ){ inicio=NULL; fin=NULL;}//if else{ fin=fin->ant; fin->sig=NULL;} } else{//cualquier otro nodo aux->ant->sig=aux->sig; aux->sig->ant=aux->ant; } delete(aux); } Inicio Fin 4  Sig 10 Ant Null 5  Sig null Ant 20 20   8  Sig null Ant 10 10   50   Inicio 4  Sig 10 Ant Null 5  Sig 50 Ant null 20   8  Sig null Ant 10 10   50   Fin Inicio 4  Sig 50 Ant Null 5  Sig 50 Ant 20 20   8  Sig null Ant 20 10   50   Fin 4  sig 10   ant Inicio Null
void main(){ int opcion; while(opcion<4){ system(&quot;cls&quot;); cout<<&quot;\n1. Insertar\n&quot;; cout<<&quot;2. Mostrar\n&quot;; cout<<&quot;3. Eliminar\n&quot;; cout<<&quot;4. Salir\n&quot;; cout<<&quot;Seleccione: &quot;; cin>>opcion; switch(opcion){ case 1:{insertar();  break;} case 2: { mostrar(); break;} case 3: {eliminar(); break;} } } }
Lista doble (Operaciones con listas) Ejercicios Utilizar una lista doblemente enlazada para controlar una lista de pasajeros de una línea aérea. El programa principal debe ser controlado por menú y permitir al usuario visualizar los datos de un pasajero determinado (cedula, nombre, apellido, destino), insertar un nodo , eliminar un pasajero de la lista.  Crear una lista doble con las edades de 10 personas y una función que calcule el promedio
Lista circular (Operaciones con listas) #include <iostream.h> #include <iostream> struct nodo{ int dato; nodo *sig; }*inicio=NULL, *nuevo=NULL, *ant, *aux, *sigue; void insertar() { nuevo=new (nodo); cout<<&quot;Elemento: &quot;; cin>>nuevo->dato; if(inicio==NULL){ inicio=nuevo; nuevo->sig=inicio; }else { ant=inicio; aux=inicio->sig; while(aux!=inicio) {ant=aux; aux=aux->sig;} ant->sig=nuevo; nuevo->sig=inicio; } } 5  Sig 10 10   ant Inicio 5  Sig 20 10   Ant 10 Inicio 4  Sig 10 Ant=10 Aux=10 20
void mostrar_circular(){ if(inicio!=NULL){//lista no vacia ant=inicio; aux=inicio->sig; cout<<ant->dato<<&quot;\n&quot;; while((aux!=inicio)&&(aux!=NULL)){ cout<<aux->dato<<&quot;\n&quot;; aux=aux->sig; } } } int contar_nodos(){ int cant=1; ant=inicio; aux=inicio->sig; while(aux!=inicio){ cant++; aux=aux->sig; } return(cant); } 5  Sig 20 10   Ant 10 Inicio 4  Sig 10 Ant=10 Aux=20 20
void menu(){ int opcion; while(opcion<4){ system(&quot;cls&quot;); cout<<&quot;1. Insertar\n&quot;; cout<<&quot;2. Mostrar\n&quot;; cout<<&quot;3. Contar Nodos\n&quot;; cout<<&quot;4. Salir\n&quot;; cout<<&quot;Seleccione: &quot;; cin>>opcion; switch(opcion){ case 1:{insertar();  break;} case 2: { mostrar_circular(); break;} case 3: { cout<<&quot;La lista tiene: &quot;<<contar_nodos()<<&quot; nodos\n&quot;; break;} } } } void main(){ menu(); }
Hacer un programa que almacene en una Lista Circular, la nota definitiva de 10 alumnos de lenguajes de programación, y muestre la nota más alta y el promedio de la sección. Lista circular (Operaciones con listas)
Pila  #include <iostream.h> struct nodo{ int num; nodo *ant; }*inicio=NULL, *aux, *nuevo; void empilar(){ nuevo=new (nodo); cout<<&quot;Elemento: &quot;; cin>>nuevo->num; if(inicio==NULL){ nuevo->ant=NULL; inicio=nuevo; } else{ nuevo->ant=inicio; inicio=nuevo; } } void desempilar(){ aux=inicio; if(aux==NULL) cout<<&quot;Pila Vacia\n&quot;; else if(aux->ant==NULL) inicio=NULL; else inicio=inicio->ant; delete(aux); cout<<&quot;elemento borrado\n&quot;; } void mostrar(){ aux=inicio; if (aux==NULL) cout<<&quot;\nLa pila esta vacia\n&quot;; while(aux!=NULL){ cout<<aux->num<<&quot;\n&quot;; aux=aux->ant; } }
void main(){ int opcion; while(opcion<4){   cout<<&quot;1. Empilar\n&quot;;   cout<<&quot;2. Desempilar\n&quot;;   cout<<&quot;3. Mostrar\n&quot;;   cout<<&quot;4. Salir\n&quot;;   cout<<&quot;Seleccione una opcion: &quot;;   cin>>opcion;   switch(opcion){   case 1:{empilar(); break;}   case 2:{desempilar(); break;}   case 3:{mostrar(); break;}   }//sw }//w }//v

Apuntadores y listas

  • 1.
    REPÚBLICA BOLIVARIANA DEVENEZUELA MINISTERIO DEL PODER POPULAR PARA LA DEFENSA UNIVERSIDAD NACIONAL EXPERIMENTAL DE LA FUERZA ARMADA NÚCLEO FALCÓN - EXTENSIÓN PUNTO FIJO Apuntadores / Estructura de datos lineales Docente: Licda. Marialix Quintero Punto Fijo, Mayo de 2011
  • 2.
    Una de lasaplicaciones más interesantes y potentes de la memoria dinámica y los punteros son las estructuras dinámicas de datos. Las estructuras básicas disponibles en C y C++ tienen una importante limitación: no pueden cambiar de tamaño durante la ejecución. Los arreglos están compuestos por un determinado número de elementos, número que se decide en la fase de diseño, antes de que el programa ejecutable sea creado. En muchas ocasiones se necesitan estructuras que puedan cambiar de tamaño durante la ejecución del programa. Por supuesto, podemos hacer 'arrays' dinámicos, pero una vez creados, tu tamaño también será fijo, y para hacer que crezcan o diminuyan de tamaño, deberemos reconstruirlas desde el principio, por este motivo los arrays no hacen un uso eficiente de la memoria.
  • 3.
    OBJETIVOS Entender laeficacia del manejo de la memoria dinámica a través del uso de apuntadores Lograr un uso eficiente de las estructuras de datos lineales.
  • 4.
    Definición. Ventajas ydesventajas. Declaración / Inicialización Punteros NULL y void Punteros o apuntadores
  • 5.
    Punteros o apuntadores(Direcciones en memoria) El proceso de asignación dinámica de memoria permite crear y destruir variables en tiempo de ejecución (variables dinámicas). Cuando una variable se declara, se asocian tres atributos fundamentales con la misma: su nombre, su tipo y su dirección en memoria. Ejemplo: int n; / * asocia al nombre n, el tipo int y la dirección de alguna posición de memoria donde se almacena el valor de n* / Al valor de una variable se accede por medio de su nombre. Por ejemplo, se puede imprimir el valor de n con la sentencia: cout<<n; A la dirección de la variable se accede por medio del operador de dirección &. Por ejemplo, se puede imprimir la dirección de n con la sentencia: cout<<&n; Ox4f f fd34 n int
  • 6.
    Ejemplo: Hacer unprograma muestre por pantalla el valor y la dirección de una variable x de tipo entero. #include <stdio.h> void main() { int n = 75; cout<<”el valor de n es: ”<<n; cout<<”la dirección de memoria de n es: ”<<&n; } Ojo: la dirección viene dada en hexadecimal Punteros o apuntadores (Direcciones en memoria)
  • 7.
    L as variablesvistas hasta este momento contienen valores de datos, por el contrario las variables punteros contienen valores que son direcciones de memoria donde se almacenan datos. En resumen, un puntero es una variable que contiene una dirección de memoria, y utilizando punteros su programa puede realizar muchas tareas que no sería posible utilizando tipos de datos estándar. Punteros o apuntadores (Definición) Puntero= variable dirección de memoria dirección de memoria de otra variable = Puntero a punta a otra variable
  • 8.
    Cuando se telefoneaa una persona, se utiliza un puntero (el número de teléfono que se marca). Punteros o apuntadores (Ejemplos) Cuando se envía una carta por correo, su información se entrega basada en un puntero que es la dirección de esa carta. Así pues, una dirección de correos y un número de teléfono tienen en común que ambos indican dónde encontrar algo.
  • 9.
    Punteros o apuntadores(Ventajas y desventajas) Los punteros tienen una gran utilidad, pues permiten una programación eficaz a nivel de máquina cuando se maneja la memoria del ordenador. Permiten realizar operaciones de asignación dinámica de memoria. Permiten efectuar operaciones con estructuras de datos dinámicas. Ventajas Los punteros deben usarse con precaución, ya que pueden provocar fallos en el programa difíciles de localizar, puede ser por asignación incorrecta de dirección.   Desventajas
  • 10.
    Los tipos dedatos tienen que corresponderse es decir (declaración de variable de tipo de dato). Los punteros se enlazan a tipos de datos específicos, de modo que C verificará si se asigna la dirección de un tipo de dato al tipo correcto de puntero. Así, por ejemplo, si se define un puntero a float, no se le puede asignar la dirección de un carácter o un entero. Por ejemplo, este segmento de código no funcionará: Ejemplo: float *fp; char c; fp = &c; / * no es válido * / Existen dos operadores especiales de punteros: & y *. El operador de dirección (&) devuelve la dirección de memoria de su operando. El operador de indirección (*) devuelve el contenido de la dirección apuntada por el operando. Punteros o apuntadores (Ventajas y desventajas)
  • 11.
    Inicialización Ejemplos deAsignación estática de memoria void main(){ int a; int* b; b = &a;         //El puntero 'b' apunta a 'a'. } Punteros o apuntadores (Declaración e inicialización) Declaración tipo_de_dato *nombre_var_puntero ej: int *punt; float *nuevo;
  • 12.
    Existen dos tiposde punteros especiales muy utilizados en el tratamiento de sus programas: los punteros void y null (nulo). Un puntero nulo no apunta a ninguna parte -dato válido- en particular, es decir, «un puntero nulo no direcciona ningún dato válido en memoria». Un puntero nulo se utiliza para proporcionar a un programa un medio de conocer cuando una variable puntero no direcciona a un dato válido. Para declarar un puntero nulo se utiliza la macro NULL, definida en los archivos de cabecera STDEF . H, STDIO. H, STDLIB. H y STRING. H. Se debe incluir uno o más de estos archivos de cabecera antes de que se pueda utilizar la macro NULL. Ejemplos: char *p = NULL; Estático nuevo->sig=NULL; Dinámico En C se puede declarar un puntero de modo que apunte a cualquier tipo de dato, es decir, no se asigna a un tipo de dato específico. En C se puede declarar un puntero de modo que apunte a cualquier tipo de dato, es decir, no se asigna a un tipo de dato específico. El método es declarar el puntero como un puntero void *, denominado puntero genérico. Punteros o apuntadores (Punteros Null y void)
  • 13.
    Definición. Tipos delistas. Operaciones con listas. Listas lineales
  • 14.
    Las estructuras dinámicasnos permiten crear estructuras de datos que se adapten a las necesidades reales a las que suelen enfrentarse nuestros programas. Pero no sólo eso, también nos permitirá crear estructuras de datos muy flexibles, ya sea en cuanto al orden, la estructura interna o las relaciones entre los elementos que las componen. Las estructuras de datos están compuestas de otras pequeñas estructuras a las que llamaremos nodos o elementos, que agrupan los datos con los que trabajará nuestro programa y además uno o más punteros autoreferenciales, es decir, punteros a objetos del mismo tipo nodo. Una estructura básica de un nodo para crear listas de datos seria: struct nodo { int dato; struct nodo *sig; }; Listas lineales (Definición)
  • 15.
    Tipos de listasSimples Circulares Doble El último elemento tiene que apuntar NULL. En las listas hay un nodo especial que es el primero ya que guarda el inicio de la lista y a través de ese nodo se puede recorrer la lista. Si el nodo inicial es NULL indica que la lista está vacia.
  • 16.
    Es una coleccióno secuencia de elementos dispuestos uno detrás de otro, en la que cada elemento se conecta al siguiente elemento por un «enlace» o «puntero». La idea básica consiste en construir una lista cuyos elementos llamados nodos se componen de dos partes o campos: la primera parte o campo contiene la información y la segunda parte el puntero que guarda la dirección de memoria del siguiente nodo de la lista o valdrá NULL si es el último elemento. En las listas abiertas existe un nodo especial: el primero. Normalmente diremos que nuestra lista es un puntero a ese primer nodo y llamaremos a ese nodo la cabeza de la lista. Eso es porque mediante ese único puntero podemos acceder a toda la lista. Cuando el puntero que usamos para acceder a la lista vale NULL, diremos que la lista está vacía. “LAS LISTAS SON ORDENADAS” Lista simple o abierta
  • 17.
    Declaración: struct nodo{int dato; struct nodo *siguiente; } *nuevo,*aux,*ant, *inicio=NULL; Lista simple o abierta (Operaciones con listas) Inicialización: inicio=NULL; Insertar Caso 1: Lista Vacía El proceso es muy simple, bastará con comprobar si la lista==NULL: nuevo->siguiente apunte a NULL. Lista apunte a nuevo. Código if (inicio==NULL){ nuevo=new nodo; nuevo->dato=elem; nuevo->sig=NULL; inicio=nuevo; } 10 NULL
  • 18.
    Caso 2: Insertarun elemento en la primera posición de la lista (menor que el 1er elemento) El proceso sigue siendo muy sencillo: Hacemos que nodo->siguiente apunte a Lista. Hacemos que Lista apunte a nodo. Lista simple o abierta (Operaciones con listas) Código: else if (elem<=inicio->dato){ nuevo=new nodo; nuevo->dato=elem; nuevo->sig=inicio; inicio=nuevo; } 10 NULL 5 sig 10 50
  • 19.
    Caso 3: Insertarun elemento después de un nodo cualquiera de la lista Procedimiento Recorrer la lista e ir guardando el anterior cuando se encuentre la posición correcta, el anterior debe apuntar al nuevo nodo y el nuevo->siguiente a la posición siguiente del anterior. Lista simple o abierta (Operaciones con listas) else { aux=inicio; while (aux!=NULL){ if (elem<aux->dato) break; ant=aux; aux=aux->sig; } nuevo=new nodo; nuevo->dato=elem; ant->sig=nuevo; nuevo->sig=aux; } 10 NULL 5 sig Aux=10-50 Elem=7 Ant=10 7 NULL 10 50 20 5 sig 10 7 sig 20 10 NULL 50
  • 20.
    Recorrer / Mostrarvoid mostrar() { nodo *aux; aux=inicio; while(aux!=NULL){ cout<<&quot;\t&quot;<<aux->dato<<&quot;\n&quot;; aux=aux->sig;} aux=lista;} Lista simple o abierta (Operaciones con listas) 5 sig 10 7 sig 20 10 NULL 50
  • 21.
    Buscar / Eliminar: Se debe recorrer la lista buscando el elemento a borrar, tomando en cuenta su posición en la lista: si es el primer elemento, el último o esta en el medio. void eliminar(int elem) { aux=inicio; while (aux!=NULL){ if (elem==aux->dato) break; ant=aux; aux=aux->sig; }//while if(aux==NULL) cout<<&quot;elemento no encontrado\n&quot;; else{ if (aux==inicio)//primer elemento inicio=aux->sig; else if (aux->sig==NULL)//ultimo ant->sig=NULL; else ant->sig=aux->sig; delete(aux);} } Lista simple o abierta (Operaciones con listas) 5 sig 10 7 sig 20 10 NULL 50 Aux=10-20 Elem=7 Ant=10
  • 22.
    Cuerpo del programaLibrería: #include <iostream.h> void main(){ int op; while (op<4) { cout<<&quot;Listas Dinamicas - Menu Principal\n\n&quot;; cout<<&quot;1.Insertar\n&quot;; cout<<&quot;2.Eliminar\n&quot;; cout<<&quot;3.Mostrar\n&quot;; cout<<”4.Salir\n\n&quot;; cout<<&quot;Seleccione una opcion: &quot;; cin>>op; int dat; switch (op){ case 1: { cout<<&quot;Dato: &quot;; cin>>dat; insertar(dat); break; } case 2: { cout<<&quot;Dato: &quot;; cin>>dat; eliminar(dat); break;} case 3:{ mostrar(); break; } } } } Lista simple o abierta (Operaciones con listas)
  • 23.
    Ejercicios propuestos delistas simple Escribir una función que imprima el número de nodos de una lista simple. Escribir una función que elimine el nodo que ocupa la posición i (dada por el usuario) de una lista simple, siendo el nodo inicio que ocupa la posición n°1. Escribir una función que no permita insertar datos no repetidos.
  • 24.
    Declaración: struct nodo{int elem; nodo *sig; nodo *ant; }*inicio=NULL, *fin=NULL, *aux, *nuevo; Lista doble (Operaciones con listas) 5 sig 10 ant void mostrar(){ aux=inicio; if (aux==NULL) cout<<&quot;\nLista Vacia&quot;; while(aux!=NULL){ cout<<aux->elem<<&quot;\t&quot;; aux=aux->sig; } } Inicio 4 Sig 10 Ant Null 5 Sig 80 Ant 20 20 8 Sig null Ant 80 10 50 8 Sig 50 Ant 10 80
  • 25.
    void insertar(){ intdato; nuevo=new nodo; cout<<&quot;Ingrese numero: &quot;; cin>>dato; nuevo->elem=dato; if (inicio==NULL){//lista vacia nuevo->sig=NULL; nuevo->ant=NULL; inicio=nuevo; fin=nuevo; } else if(dato<inicio->elem){//inserto al inicio nuevo->sig=inicio; nuevo->ant=NULL; inicio->ant=nuevo; inicio=nuevo; } else if(dato>fin->elem){//inserto por el final nuevo->ant=fin; nuevo->sig=NULL; fin->sig=nuevo; fin=nuevo; } else{//se recorre la lista aux=inicio; while(aux!=NULL){ if(dato<aux->elem) break; aux=aux->sig; }//while //se enlaza con el siguiente nuevo->sig=aux; nuevo->ant=aux->ant; aux->ant->sig=nuevo; aux->ant=nuevo; } } 5 sig 10 ant 4 Sig 10 20 Ant Null 5 Sig null 10 Ant 20 Inicio Inicio Nuevo-inicio Inicio Inicio Null Nuevo 4 Sig 10 Ant Null 5 Sig 50 Ant 20 20 8 Sig null Ant 10 10 50 6 sig 80 ant Null Inicio Inicio 4 Sig 10 Ant Null 5 Sig 80 Ant 20 20 8 Sig null Ant 80 10 50 8 Sig 50 Ant 10 80 Nuevo
  • 26.
    void eliminar(){ intdato_eli; cout<<&quot;Ingrese dato a eliminar: &quot;; cin>>dato_eli; aux=inicio; while(aux!=NULL){ if(dato_eli==aux->elem) break; aux=aux->sig; } //se evaluan 4 casos if(aux==NULL){//no encontrado cout<<&quot;elemento no encontrado\n&quot;; } else if(aux==inicio){//borra el 1er nodo if((aux->sig==NULL) &&(aux->ant==NULL) ){ inicio=NULL; fin=NULL;} else{ inicio=inicio->sig; inicio->ant=NULL;} } else if (aux==fin){//borra el ultimo nodo if((aux->sig==NULL) &&(aux->ant==NULL) ){ inicio=NULL; fin=NULL;}//if else{ fin=fin->ant; fin->sig=NULL;} } else{//cualquier otro nodo aux->ant->sig=aux->sig; aux->sig->ant=aux->ant; } delete(aux); } Inicio Fin 4 Sig 10 Ant Null 5 Sig null Ant 20 20 8 Sig null Ant 10 10 50 Inicio 4 Sig 10 Ant Null 5 Sig 50 Ant null 20 8 Sig null Ant 10 10 50 Fin Inicio 4 Sig 50 Ant Null 5 Sig 50 Ant 20 20 8 Sig null Ant 20 10 50 Fin 4 sig 10 ant Inicio Null
  • 27.
    void main(){ intopcion; while(opcion<4){ system(&quot;cls&quot;); cout<<&quot;\n1. Insertar\n&quot;; cout<<&quot;2. Mostrar\n&quot;; cout<<&quot;3. Eliminar\n&quot;; cout<<&quot;4. Salir\n&quot;; cout<<&quot;Seleccione: &quot;; cin>>opcion; switch(opcion){ case 1:{insertar(); break;} case 2: { mostrar(); break;} case 3: {eliminar(); break;} } } }
  • 28.
    Lista doble (Operacionescon listas) Ejercicios Utilizar una lista doblemente enlazada para controlar una lista de pasajeros de una línea aérea. El programa principal debe ser controlado por menú y permitir al usuario visualizar los datos de un pasajero determinado (cedula, nombre, apellido, destino), insertar un nodo , eliminar un pasajero de la lista. Crear una lista doble con las edades de 10 personas y una función que calcule el promedio
  • 29.
    Lista circular (Operacionescon listas) #include <iostream.h> #include <iostream> struct nodo{ int dato; nodo *sig; }*inicio=NULL, *nuevo=NULL, *ant, *aux, *sigue; void insertar() { nuevo=new (nodo); cout<<&quot;Elemento: &quot;; cin>>nuevo->dato; if(inicio==NULL){ inicio=nuevo; nuevo->sig=inicio; }else { ant=inicio; aux=inicio->sig; while(aux!=inicio) {ant=aux; aux=aux->sig;} ant->sig=nuevo; nuevo->sig=inicio; } } 5 Sig 10 10 ant Inicio 5 Sig 20 10 Ant 10 Inicio 4 Sig 10 Ant=10 Aux=10 20
  • 30.
    void mostrar_circular(){ if(inicio!=NULL){//listano vacia ant=inicio; aux=inicio->sig; cout<<ant->dato<<&quot;\n&quot;; while((aux!=inicio)&&(aux!=NULL)){ cout<<aux->dato<<&quot;\n&quot;; aux=aux->sig; } } } int contar_nodos(){ int cant=1; ant=inicio; aux=inicio->sig; while(aux!=inicio){ cant++; aux=aux->sig; } return(cant); } 5 Sig 20 10 Ant 10 Inicio 4 Sig 10 Ant=10 Aux=20 20
  • 31.
    void menu(){ intopcion; while(opcion<4){ system(&quot;cls&quot;); cout<<&quot;1. Insertar\n&quot;; cout<<&quot;2. Mostrar\n&quot;; cout<<&quot;3. Contar Nodos\n&quot;; cout<<&quot;4. Salir\n&quot;; cout<<&quot;Seleccione: &quot;; cin>>opcion; switch(opcion){ case 1:{insertar(); break;} case 2: { mostrar_circular(); break;} case 3: { cout<<&quot;La lista tiene: &quot;<<contar_nodos()<<&quot; nodos\n&quot;; break;} } } } void main(){ menu(); }
  • 32.
    Hacer un programaque almacene en una Lista Circular, la nota definitiva de 10 alumnos de lenguajes de programación, y muestre la nota más alta y el promedio de la sección. Lista circular (Operaciones con listas)
  • 33.
    Pila #include<iostream.h> struct nodo{ int num; nodo *ant; }*inicio=NULL, *aux, *nuevo; void empilar(){ nuevo=new (nodo); cout<<&quot;Elemento: &quot;; cin>>nuevo->num; if(inicio==NULL){ nuevo->ant=NULL; inicio=nuevo; } else{ nuevo->ant=inicio; inicio=nuevo; } } void desempilar(){ aux=inicio; if(aux==NULL) cout<<&quot;Pila Vacia\n&quot;; else if(aux->ant==NULL) inicio=NULL; else inicio=inicio->ant; delete(aux); cout<<&quot;elemento borrado\n&quot;; } void mostrar(){ aux=inicio; if (aux==NULL) cout<<&quot;\nLa pila esta vacia\n&quot;; while(aux!=NULL){ cout<<aux->num<<&quot;\n&quot;; aux=aux->ant; } }
  • 34.
    void main(){ intopcion; while(opcion<4){ cout<<&quot;1. Empilar\n&quot;; cout<<&quot;2. Desempilar\n&quot;; cout<<&quot;3. Mostrar\n&quot;; cout<<&quot;4. Salir\n&quot;; cout<<&quot;Seleccione una opcion: &quot;; cin>>opcion; switch(opcion){ case 1:{empilar(); break;} case 2:{desempilar(); break;} case 3:{mostrar(); break;} }//sw }//w }//v