Sie sind auf Seite 1von 27

Instituto Politécnico Nacional

Escuela Superior de Ingeniería Mecánica y Eléctrica


Unidad Zacatenco

“Estructura y Base de
Datos”

Profra.: Lic. Cortes Hernández Lilia

“LISTAS CIRCULARES”

Grupo 3C4V

PRESENTAN:

Domínguez Lozano Rubén


Bárcenas Martínez Bernardo
Martínez Cedillo Marco Antonio

Página
1
*ÍNDICE

Desarrollo del tema.............................................................................................3

Operaciones con listas circulares........................................................................4

Inserción de una lista vacía.................................................................................5

Inserción de una lista no vacía............................................................................6

Eliminación al inicio de una lista........................................................................8

Mostrar lista.......................................................................................................11

Destrucción de una lista....................................................................................12

*Ejemplos

Números al azar................................................................................................13

Búsqueda..........................................................................................................19

Inserción de un elemento al principio de la lista..............................................20

Manual Técnico y de Usuario...........................................................................23

BIBLIOGRAFÍA

Programación en C

Autores: Luis Joyanes Aguilar y Andres Castillo Sanz

Ed. Mc Graw Hill

Primera edición

Aprenda C en 21 dias

Autor: Lucas Sanchez Garcia

Ed. Adison Wensly

Tercera edición

Página
2
*Desarrollo del Tema
Listas Circulares

La lista circular es una especie de lista enlazada simple o doblemente enlazada, pero que
posee una característica adicional para el desplazamiento dentro de la lista, “ésta no
tiene,fin”.
Para que la lista sea sin fin, el puntero siguiente del último elemento apuntará hacia el
1er elemento de la lista en lugar de apuntar al valor NULL, como hemos visto en el caso
de listas enlazadas simples o doblemente enlazadas
En las listas circulares, nunca se llega a una posición en la que ya no sea posible
desplazarse.
Cuando se llegue al último elemento, el desplazamiento volverá a comenzar desde el
primer elemento.

III. La construcción del modelo de un elemento de la lista

Para definir un elemento de la lista, el tipo struct será utilizado.


El elemento de la lista contendrá un campo dato y un puntero siguiente.
El puntero siguiente debe ser del mismo tipo que el elemento, en caso contrario no
podrá apuntar a elemento siguiente.

El puntero siguiente permitirá el acceso hacia el próximo elemento.

typedef struct ElementoLista {


char *dato;
struct ElementoLista *siguiente;
}Elemento;

Página
3
Para tener el control de l alista es preferible guardar ciertos elementos: el primer
elemento, el último elemento, el número de elementos.
Para ello, otra estructura será utilizada (no es obligatorio, pueden ser utilizadas
variables)

typedef struct ListaIdentificar {


Elemento *inicio;
Elemento *fin;
int tamaño;
}Lista;

El puntero inicio contendrá la dirección del primer elemento de la lista.


El puntero fin contendrá la dirección del ultimo elemento de la lista.
La variable tamaño contiene el número de elementos.
Cualquiera que sea la posición en la lista, los punteros inicio y fin siempre apuntaran
hacia el 1er y el último elemento respectivamente.
El campo tamaño contendrá el número de elementos de la lista cualquiera sea la
operación efectuada sobre la lista.

IV. Operaciones sobre las listas circulares


A. Inicialización

Modelo de la función

void inicialización (Lista *lista);

Esta operación debe ser hecha antes de cualquier otra operación sobre la lista.
Inicializa el puntero inicio y el puntero fin con el puntero NULL, y el tamaño con el
valor 0.

La función:

void inicialización (Lista *lista){


lista->inicio = NULL;
lista->fin = NULL;
tamaño = 0;
}

Página
4
B. Inserción de un elemento en la lista

A continuación el algoritmo de inserción y registro de los elementos:

• declaración del elemento a insertar


• asignación de la memoria para el nuevo elemento
• rellenar el contenido del campo de datos
• actualizar los punteros hacia el 1er y ultimo elemento si es necesario.
o Caso particular: en una lista con un solo elemento, el 1er elemento es al
mismo tiempo el ultimo.

Actualizar el tamaño de la lista.

1. Inserción en una lista vacía

Modelo de la función:

int ins_lista_circ_vacia(Lista * lista, char *dato);

La función devuelve -1 en caso de error, si no devuelve 0.

Etapas:

• asignación de memoria para el nuevo elemento


• rellenar el campo de datos del nuevo elemento
• el puntero siguiente del nuevo elemento apuntará hacia si mismo (es la etapa
que vuelve a la lista circular)
• los punteros inicio y fin apuntaran hacia el nuevo elemento
• el tamaño es actualizado

Página
5
La función:

/* inserción en una lista vacía */


int ins_lista_circ_vacia(Lista * lista, char *dato){
Elemento *nuevo_elemento;
if ((nuevo_elemento = (Elemento *) malloc (sizeof (Elemento)))
== NULL)
return -1;
if ((nuevo_elemento->dato = (char *) malloc (50 * sizeof (char)))
== NULL)
return -1;
strcpy (nuevo_elemento->dato, dato);

nuevo_elemento->siguiente = nuevo_elemento;
lista->inicio = nuevo_elemento;
lista->fin = nuevo_elemento;
lista->tamaño++;
return 0;
}

2. Inserción en una lista no vacía

Modelo de la función:

int ins_lista_circ(Lista * lista, Elemento *actual, char *dato);

La función devuelve -1 en caso de error, si no devuelve 0.

Etapas:

• asignación de memoria para el nuevo elemento


• rellenar el campo de datos del nuevo elemento
• el puntero siguiente del nuevo elemento apunta hacia la dirección del primer
elemento (conservar la lista circular)
• el puntero inicio no cambia
• el puntero fin apunta hacia el nuevo elemento
• el tamaño se incrementa en una unidad

Página
6
La función:

/* inserción en una lista no vacía */


int ins_lista_circ(Lista * lista, Elemento *actual, char *dato){
Elemento *nuevo_elemento;
if ((nuevo_elemento = (Elemento *) malloc (sizeof (Elemento)))
== NULL)
return -1;
if ((nuevo_elemento->dato = (char *) malloc (50 * sizeof (char)))
== NULL)
return -1;
strcpy (nuevo_elemento->dato, dato);

if(actual != lista->fin)
return -1;

nuevo_elemento->siguiente = actual->siguiente;
actual->siguiente = nuevo_elemento;
lista->fin = nuevo_elemento;
lista->tamaño++;
Return 0;
}

Página
7
C. Eliminación de un elemento en la lista

A continuación el algoritmo de eliminación de un elemento de la lista:

• uso de un puntero temporal para guardar la dirección de los elementos a eliminar


• el elemento a eliminar se encuentra después del elemento actual

Hacer apuntar el puntero siguiente del elemento actual hacia la dirección del puntero
siguiente del elemento a eliminar

• liberar la memoria ocupada por el elemento eliminado


• actualizar el tamaño de la lista

Para eliminar un elemento de la lista hay varias situaciones:

• 1. Eliminación dentro de la lista


• 2. Eliminación del último elemento de la lista

1. Eliminación al inicio de la lista

Modelo de la función:

int sup_list_circ(Lista *lista);

La función devuelve -1 en caso de error, si no devuelve 0.

Etapas:

• el puntero sup_elemento contendrá la dirección del 1er elemento


• el puntero inicio apuntara hacia el 2do elemento
• el puntero siguiente del ultimo elemento apuntara hacia el 1er elemento (que era
el 2do antes de la eliminación)
• el tamaño de la lista disminuirá 1 elemento.

Página
8
La función:

/* eliminación al inicio de la lista */


int sup_lista_circ(Lista * lista){
if (lista->tamaño < 2)
return -1;
Elemento *sup_element;

sup_elemento = lista->inicio;
lista->inicio = lista->inicio->siguiente;
lista->fin->siguiente = lista->inicio;

free (sup_elemento->dato);
free (sup_elemento);
lista->tamaño--;
return 0;
}

2. Eliminación en una lista con un solo elemento

Modelo de la función:

int sup_list_circ_unica(Lista *lista);

Página
9
La función devuelve -1 en caso de error, si no devuelve 0.

Etapas:

• el puntero sup_elemento contendrá la dirección del elemento (la lista contiene


un solo elemento)
• el puntero inicio apuntara hacia NULL
• el puntero fin apuntara hacia NULL
• el tamaño de la lista disminuirá un elemento.

La función:

/* eliminación en una lista con un solo elemento*/


int sup_lista_circ_unica(Lista *lista){
if (lista->tamaño != 1)
return -1;
Elemento *sup_elemento;

sup_elemento = lista->inicio;
lista->inicio = NULL;
lista->fin = NULL;

free (sup_elemento->dato);

Página
10
free (sup_elemento);
lista->tamaño--;
return 0;
}

D. Mostrar la lista

Para mostrar la lista completa, es necesario posicionarse al inicio de la lista (el puntero
inicio lo permitirá). Luego, utilizando el puntero siguiente de cada elemento, la lista es
recorrida del 1er al ultimo elemento.
En comparación con las listas simples y doblemente enlazadas, en el que la condición
para detenerse esta dada por el puntero siguiente del ultimo elemento, que vale NULL,
para la lista circular, no hay punto de detención, a menos que elijamos uno.

A continuación dos variantes de visualización:

• Mostrar la lista (del 1er al último elemento)


• Mostrar la lista sin una condición para detenerse.

1. Mostrar la lista (del 1er al último elemento)

Utilizaremos el tamaño de la lista como la condición para detenerse.

La función:

/* mostrar la lista */
void mostrar (Lista * lista){
Elemento *actual;
actual = lista->inicio;
int i;
for(i=0;i<lista->tamaño;++i){
printf ("%p - %s\n", actual, actual->dato);
actual = actual->siguiente;
}
}
2. Mostrar la lista sin una condición para detenerse (indefinidamente)

La función:

/* recorrer la lista indefinidamente*/

Página
11
void mostrar_indefinidamente (Lista * lista){
Elemento *actual;
actual = lista->inicio;
while (1){
printf ("%p - %s\n", actual, actual->dato);
actual = actual->siguiente;
}
}

E. Destrucción de la lista

Para destruir la lista completa, he utilizado al eliminación al inicio de la lista ya que el


tamaño es mayor a 1, luego la eliminación en una lista con un solo elemento.

La función:

/* destruir la lista */
void destruir (Lista * lista){
while (lista->tamaño > 0){
if (lista->tamaño > 1)
sup_lista_circ (lista);
else
sup_lista_circ_unica(lista);
}

Página
12
*Ejemplos

Programa Numeros al Azar: (ejemplo1.exe)

En este programa se escriben las declaraciones y funciones necesarias para trabajar en


una lista circular.

Análisis del problema:

El programa se estructura de la siguiente forma:.Primeramente se hacen las


declaraciones necesarias para tratar la Lista Circular.El programa principal se encarga
de realizar las llamadas correspondientes.VaciaLc. Es una función que crea una lista
circular vacía..EsVaciaLc. Es una función que da verdadero cuando la lista circular esta
vacía..NuevoNodoLc. Es una función que devuelve un puntero a un nuevo nodo en el
que se ha almacenado el dato x..InsertaListaCircular. Realiza la inserción de una lista
circular del valor dato. Lo hace teniendo en cuenta que primero es un puntero que
apunta al último elemento que se añadió a la lista. Lo que hace es insertar un nuevo
nodo en la Lista Circular como último elemento, para lo cual aparte de realizar los
correspondientes enlaces, mueve el puntero primero para que apunte siempre al último
elemento que se añadió. De esta forma el primer elemento de la lista siempre estará en
el nodo Primero->sig..GeneraPorElFinalLc. Crea una lista circular de números enteros
aleatorios, realizando las inserciones con la función InsertaListaCircular.

.EscribeListaLc. Se encarga de eliminar el primer nodo de la lista circular que como


sabemos estará siempre en Primero->sig. Solo hay que tener en cuenta que si la lista
esta vacía no se puede borrar. Si tiene un solo dato la lista se quedara vacía y habrá que
liberar memoria. Si tiene más de un dato habrá que mover el puntero Primero->sig a
Primero->sig->sig; y liberar la memoria del nodo que hemos puenteado.

.EliminarLc. Se encarga de buscar la primera aparición de dato y borrarla de la lista


circular. Lo hace de la siguiente forma. Si la lista esta vacía no hay nada que hacer. En
otro caso con una variable lógica enc y con un puntero ptr realiza la búsqueda del dato,
controlando no realizar un bucle infinito. Una vez encontrado el elementó se realiza el
borrado teniendo en cuenta: si la lista contiene un solo valor se quedará vacía; si el nodo
a borrar por Primero, habrá que mover este puntero; en otro caso no habrá que moverlo.
Siempre que se borre un nodo habrá que puentearlo.

Página
13
#include<stdio.h>

#include<stdlib.h>

#include<time.h>

#define MX 100

#include<conio.h>

typedef int Item;

typedef struct NuevoNodo

Item el;

struct NuevoNodo*sig;

}NodoLc;

void VaciaLc(NodoLc**Primero);

int EsVaciaLc(NodoLc *Primero);

NodoLc* NuevoNodoLc(Item x);

void InsertaListaCircular(NodoLc **Primero, Item datos);

void GeneraPorElFinalLc(NodoLc **Primero);

void EscribeListaLc(NodoLc *Primero);

void EliminarPrimeroLc(NodoLc **Primero);

void main (void)

//clrscr();

NodoLc *Primero;

GeneraPorElFinalLc(&Primero);

EscribeListaLc(Primero);

getch();

Página
14
}

void VaciaLc(NodoLc**Primero)

*Primero=NULL;

int EsVaciaLc(NodoLc *Primero)

return (Primero==NULL);

NodoLc*NuevoNodoLc(Item x)

NodoLc *nn;

nn=(NodoLc*)malloc(sizeof(NodoLc));

nn-> el = x; nn-> sig=nn;

return nn;

void InsertaListaCircular (NodoLc **Primero,Item dato)

NodoLc* nn;

nn=NuevoNodoLc(dato);

if (*Primero!=NULL)

//nn->sig= *Lc ->sig;

(*Primero) ->sig=nn;

*Primero = nn;

Página
15
void GeneraPorElFinalLc(NodoLc **Primero)

Item d;

NodoLc *p;

p=NULL; randomize();

for (d=random(MX); d; )

InsertaListaCircular (&p,d);

d= random (MX);

*Primero=p;

void EscribeListaLc(NodoLc *Primero)

NodoLc *ptr;

int k=0;

ptr= Primero;

if(ptr!=NULL)

ptr=ptr->sig;

do

k++;

if(k%10==0)

printf("\n");

printf("%d",ptr->el);

Página
16
}

else

printf(" ");

printf("%d",ptr->el);

ptr=ptr->sig;

while (ptr!=Primero->sig);

void EliminaPrimeroLc(NodoLc **Primero)

NodoLc *ptr, *p;

ptr=*Primero;

if(ptr!=NULL)

p=ptr->sig; //p hay que borrarlo

if (p==ptr)

*Primero=NULL;

else

ptr->sig=p->sig;

free(p);

void EliminarLc (NodoLc** Primero,Item dato)

NodoLc *ptr,*p;

int enc = 0;

Página
17
ptr = *Primero;

if (ptr==NULL)

return;

//busqueda mientras no encontrado y no de la vuelta

while ((ptr->sig!=*Primero)&&(!enc))

enc=(ptr->sig->el==dato);

if (!enc)

ptr = ptr->sig;

}enc = (ptr->sig->el==dato); //aqui se debe encontrar el dato

if (enc)

{p=ptr->sig;

if(*Primero==(*Primero)->sig) //solo hay un dato

*Primero=NULL;

else

if (p==*Primero)

*Primero= ptr;

ptr->sig=p->sig;

free(p);

Ejecutado

Página
18
Programa: Búsqueda (lista cir.exe)

Definición:

La Búsqueda su objetivo es encontrar un dato en el arreglo Info, si lo encuentra lo


desplegara en la pantalla, si no lo encuentra no desplegara nada ya que el dato no se
encuentra en el arreglo Info.

Programa:

#include <conio.h>

#include <iostream.h>

int Busqueda(int Info[8],int Indice[8],int Inicio,int Disp,int


Elemento);

void main()

int Info[8]={0,10,0,9,5,3,0,20};

int Indice[8]={5,7,6,1,0,3,-999,4};

int Inicio=0,Disp=2,Elemento,Res;

cout<<"Que Numero deseas buscar?";

cin>>Elemento;

Res=Busqueda(Info,Indice,Inicio,Disp,Elemento);

if(Res==-999)

cout<<"Dato No Encontrado...";

getch();

int Busqueda(int Info[8],int Indice[8],int Inicio,int Disp,int


Elemento)

int Apuntador=Indice[Inicio];

while(Apuntador!=Inicio)

Página
19
{

if(Elemento==Info[Apuntador])

cout<<"Numero "<<Info[Apuntador]<<" encontrado...";

return Apuntador;

Apuntador=Indice[Apuntador];

return Apuntador;

*Inserción de un elemento (numero) al Principio (nodo.exe)

Definición:

La Inserción al Principio básicamente busca si existe algún lugar disponible en el


arreglo Info y lo agrega como primer Nodo si es que es posible.

Página
20
Programa:

#include <conio.h>

#include <iostream.h>

void Recorrido(int Info[8],int Indice[8],int Inicio,int Disp);

void InsPr(int Info[8],int Indice[8],int Inicio,int Disp,int


Elemento);

void main()

int Info[8]={0,10,0,9,5,3,0,20};

int Indice[8]={5,7,6,1,0,3,-999,4};

int Inicio=0,Disp=2,Elemento,Res;

cout<<"Lista Original\n";

Recorrido(Info,Indice,Inicio,Disp);

cout<<"Que Numero deseas Insertar?";

cin>>Elemento;

InsPr(Info,Indice,Inicio,Disp,Elemento);

getch();

void Recorrido(int Info[8],int Indice[8],int Inicio,int Disp)

{int Apuntador=Indice[Inicio];

while(Apuntador!=Inicio)

cout<<Info[Apuntador]<<endl;

Apuntador=Indice[Apuntador];

void InsPr(int Info[8],int Indice[8],int Inicio,int Disp,int


Elemento)

Página
21
{

if(Disp!=-999)

int Apuntador=Disp;

Disp=Indice[Disp];

Info[Apuntador]=Elemento;

Indice[Apuntador]=Indice[Inicio];

Indice[Inicio]=Apuntador;

Recorrido(Info,Indice,Inicio,Disp);

else

cout<<"Overflow...";

Página
22
*Manual Técnico y de Usuario
*Inserción de un elemento (numero) al Principio

Definición:

La Inserción al Principio básicamente busca si existe algún lugar disponible en el


arreglo Info y lo agrega como primer Nodo si es que es posible.

Detalle:

Hace una comparación para ver si es posible insertar otro Elemento al arreglo Info, para
esto checa si Disp es Diferente de Nulo. Si no cumple con la condición se desplegar
“Sobre Carga” ya que no se puede insertar un Nuevo Elemento. Si es cierto Apuntador
toma el valor de Inicio, Disp cambia a Indice[Disp] ya que el primer Disp tomara el
valor del Nuevo Elemento, después de esto solo copia la información de Elemento al
arreglo Info en la posición que guarda Apuntador, Indice[Apuntador] toma el valor de
Indice[Inicio] y finalmente Indice[Inicio] toma el valor de Apuntador.

Algoritmo:

InsPr(Inicio, Disp, Info, Indice, Elemento)

Si Disp ≠ Nill entonces:

Apuntador → Disp

Disp → Indice[Disp]

Info[Apuntador] → Elemento

Indice[Apuntador] → Indice[Inicio]

Indice[Inicio] → Apuntador

Si no: Imprimir “Sobre Carga”

Salir

Diagrama:

Programa:

Página
23
#include <conio.h>

#include <iostream.h>

void Recorrido(int Info[8],int Indice[8],int Inicio,int Disp);

void InsPr(int Info[8],int Indice[8],int Inicio,int Disp,int


Elemento);

void main()

int Info[8]={0,10,0,9,5,3,0,20};

int Indice[8]={5,7,6,1,0,3,-999,4};

int Inicio=0,Disp=2,Elemento,Res;

cout<<"Lista Original\n";

Recorrido(Info,Indice,Inicio,Disp);

cout<<"Que Numero deseas Insertar?";

cin>>Elemento;

InsPr(Info,Indice,Inicio,Disp,Elemento);

getch();

void Recorrido(int Info[8],int Indice[8],int Inicio,int Disp)

int Apuntador=Indice[Inicio];

while(Apuntador!=Inicio)

cout<<Info[Apuntador]<<endl;

Apuntador=Indice[Apuntador];

void InsPr(int Info[8],int Indice[8],int Inicio,int Disp,int Elemento)

{if(Disp!=-999)

int Apuntador=Disp;

Disp=Indice[Disp];

Página
24
Info[Apuntador]=Elemento;

Indice[Apuntador]=Indice[Inicio];

Indice[Inicio]=Apuntador;

Recorrido(Info,Indice,Inicio,Disp);

else

cout<<"Overflow...";

Programa: Búsqueda

Página
25
Definición:

La Búsqueda su objetivo es encontrar un dato en el arreglo Info, si lo encuentra lo


desplegara en la pantalla, si no lo encuentra no desplegara nada ya que el dato no se
encuentra en el arreglo Info.

Detalle:

Apuntador toma el valor de Inicio, después ve si la condición cumple para efectuar un


Ciclo mientras Apuntador sea diferente de 0, si cumple lo que hace a continuación es la
comparación de Elemento (El dato que vamos a buscar) con Info[Apuntador], cuando lo
encuentre lo despliega y sale del método. Si no, regresa el valor de Apuntador para así
saber que no se encontró el dato.

Algoritmo:

Recorrido(Inicio, Info, Indice, Elemento)

Apuntador → Indice[Inicio]

Repetir mientras Apuntador ≠ Inicio

Si Elemento = Info[Apuntador] entonces:

Imprimir Info[Apuntador]

Regresa Apuntador

Apuntador → Indice[Apuntador]

Fin del ciclo

Regresar Apuntador

Diagrama:

Programa:

#include <conio.h>

Página
26
#include <iostream.h>

int Busqueda(int Info[8],int Indice[8],int Inicio,int Disp,int


Elemento);

void main()

int Info[8]={0,10,0,9,5,3,0,20};

int Indice[8]={5,7,6,1,0,3,-999,4};

int Inicio=0,Disp=2,Elemento,Res;

cout<<"Que Numero deseas buscar?";

cin>>Elemento;

Res=Busqueda(Info,Indice,Inicio,Disp,Elemento);

if(Res==-999)

cout<<"Dato No Encontrado...";

getch();

int Busqueda(int Info[8],int Indice[8],int Inicio,int Disp,int


Elemento)

int Apuntador=Indice[Inicio];

while(Apuntador!=Inicio)

{
if(Elemento==Info[Apuntador])

cout<<"Numero "<<Info[Apuntador]<<" encontrado...";

return Apuntador;

Apuntador=Indice[Apuntador];

}
return Apuntador;

Página
27