Las listas circulares (Ring Buffer)

última actualización el 7 de julio de 2009, 02:14 por Carlos-vialfa
Publicado por Carlos-vialfa

las listas circulares






Requisitos


Los tipos de datos
Las estructuras
El uso de typedef
Los punteros
La función usuario
Las listas enlazadas simples
Las listas doblemente enlazadas

I. Introducción


El objetivo de este artículo es que el lector comprenda lo que son las listas circulares

II Definición


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 hacia el elemento.
El puntero siguiente permitirá el acceso hacia el próximo elemento.

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


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 punter 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;
}

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.
    • 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



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.

La inserción se efectuara al final de la lista.

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



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;
}

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.



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);


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);
    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*/
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);
    }
}

V. Ejemplo completo


lista_circ.h


/* ---------- lista_circ.h ----------- */
typedef struct ElementoListaCirc {
    char *dato;
    struct ElementoListaCirc *siguiente;
} Element;

typedef struct ListaIdentificarCirc {
    Elemento *inicio;
    Elemento *fin;
    int tamaño;
} Lista;

/* inicialización de la lista */
void inicialización (Lista * lista);

/* INSERCION */
/* inserción en una lista vacia */
int ins_lista_circ_vacia(Lista * lista, char *dato);
int ins_lista_circ(Lista * lista, Elemento *actual, char *dato);

/* ELIMINACION */
int sup_lista_circ (Lista * lista);
int sup_lista_circ_unica (Lista * lista);

int menu (Lista *lista);
void mostrar (Lista * lista);
void mostrar_infinito (Lista * lista);
void destruir (Lista * lista);
/* -------- FIN lista_circ.h --------- */

lista_circ_function.h


/******************************\

    * lista_circ_function.h *
\******************************/
void inicialización (Lista * lista){
    lista->inicio = NULL;
    lista->fin = NULL;
    lista->tamaño = 0;
}

/* inserción en una lista vacia */
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<gras>;
    return 0;
}

/* inserción en una lista no vacia */
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<gras>;
    return 0;
}

/* eliminación al inicio de la lista */
int sup_lista_circ(Lista * lista){
    if (lista->tamaño < 2)
        return -1;
    Elemento *sup_elemento;

    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;
}

/* 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);
    free (sup_elemento);
    lista->tamaño--;
    return 0;
}

/* 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;
    }
}

/* recorrer la lista indefinidamente*/
void mostrar_infinito (Lista * lista){
    Elemento *actual;
    actual = lista->inicio;
    while (1){
        printf ("%p - %s\n", actual, actual->dato);
        actual = actual->siguiente;
    }
}

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

int menu (Lista *lista){
    int elección;     printf("********** MENU **********\n");
    if (lista->tamaño == 0){
        printf ("1. Adicion del 1er elemento\n");
        printf ("2. Quitar\n");
    }else {       
        printf ("1. Adición de un elemento\n");
        printf ("2. Eliminación al inicio (la lista debe tener al menos 2 elementos)\n");
    printf ("3. Eliminación en una lista con un solo elemento\n");
        printf ("4. Mostrar lista circular\n");
        printf ("5. Mostrar lista circular [Ctrl-C] para quitar el programa\n");
        printf ("6. Destruir la lista\n");
        printf ("7. Quitar\n");
    }
    printf ("\n\nElegir: ");
    scanf ("%d", &elección);
    getchar();
    if(lista->tamaño == 0 && elección == 2)
        elección = 7;
    return elección;
}
/* -------- FIN lista_circ_function --------- */

lista_circ.c


/**********************\

    * lista_circ.c *
\**********************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lista_circ.h"
#include "lista_circ_function.h"

int main (void)
{
    char elección;
    char *nom;
    Lista *lista;
    Elemento *actual;


    if ((lista = (Lista *) malloc (sizeof (lista))) == NULL)
    return -1;
    if ((nombre = (char *) malloc (50)) == NULL)
        return -1;
    actual = NULL;
    elección = 'o';

    inicialización (lista);

    while (elección != 7){
        elección = menu (lista);
        switch (elección){
            case 1:
                printf ("Ingrese un elemento: ");
                scanf ("%s", nombre);
                getchar ();
                if(lista->tamaño == 0)
                    ins_lista_circ_vacia (lista,nombre);
                else
                    ins_lista_circ (lista,lista->fin,nombre);
                printf ("%d elements:deb=%s, fin=%s\n",
                                        lista->tamaño,
                                        lista->inicio->dato,
                                        lista->fin->dato);
                mostrar (lista);
                break;
            case 2:
                if(lista->tamaño < 2)
                    break;
                sup_lista_circ (lista);
                if (lista->tamaño != 0)
                    printf ("%d elements:deb=%s, fin=%s\n",
                                            lista->tamaño,
                                            lista->inicio->dato,
                                            lista->fin->dato);
                mostrar(lista);
                break;
            case 3:
                if(lista->tamaño != 1)
                    break;
                sup_lista_circ_unica(lista);
                printf("La lista está vacia\n");
                break;
            case 4:
                mostrar(lista);
                break;
            case 5:
                mostrar_infinito(lista);
                break;
            case 6:
                destruir (lista);
                printf ("la lista ha sido destruida: %de elementos\n", lista->tamaño);
                break;
        }
    }
    return 0;
}

VI. Ver también



PD: El artículo original fue escrito por lami20j, contribuidor de CommentCaMarche
Mejores respuestas para « Las listas circulares (Ring Buffer) » en :
La lista enlazada simple Ver La lista enlazada simple Pre-requisitos I. Introducción II. Definición III. Construcción del modelo de un elemento de la lista IV. Operaciones sobre las listas enlazadas A. Inicialización B. Inserción de un elemento en la lista 1....
Ver la lista completa de comandos MS-DOS Ver El problema Estoy buscado la lista completa de comandos ms-dos. He buscado por todos lados, pero en vano, ya que las listas no son completas. La solución Ejecuta el intérprete de comandos ms-dos y escribe help, luego presiona Enter. Aparecerán...
Las filas en lenguaje C Ver las filas – Primero en Entrar, Primero en salir Requisitos I. Introducción II. Definición III. La construcción del modelo de un elemento de la fila IV. Operaciones sobre las filas A. Inicialización B. Inserción C. Eliminar un...
Desbloquear un contacto en Skype VerSi bloqueaste a uno de tus contactos en Skype, pero ahora quieres volverlo a admitir, entonces: Entra a Herramientas > Opciones En el menú de la izquierda, selecciona Privacidad > Personas bloqueadas y te aparecera las lista de personas...
Presentación de los artículos de la base de conocimientos VerPresentación de los artículos de la base de conocimientos 1- Los títulos 1.1 – Ejemplo 2 – Las listas 2.1 – Ejemplo recomendado 2.1.1 – Resultado 2.2 – Ejemplos no recomendados 2.2.1 – Empezar por un nivel X 2.2.1.1 – Ejemplo 2.2.1.2 –...
Crear una lista desplegable simple en Excel VerSi deseas que los datos a ingresar de las celdas de tu hoja de cálculo sean elegidos de una lista desplegable. Entonces sigue estos pasos: En una zona de la hoja activa o en otra hoja de tu documento Excel activo, ingresa los datos de la lista en...
Descargar Soft191 MP3 Player VerSoft191 MP3 Player es un reproductor de música gratuito con la peculiaridad de incluir un explorador de archivos para localizar y añadir música a las listas de reproducción que pueden ser guardadas y cargadas fácilmente. El programa reside en la...
Descargar Mufin VerEste reproductor de video nos permitira gestionar de manera eficiente toda tu coleccion musical. Su principal funcion es la de clasificar las canciones por similitud , por lo que facilitara la creacion de las listas de reproduccion de un genero...
Descargar Cuberok VerCuberok es una version de Windows del famosi reproductor Amarok Con este reproductor podramos escuchar música desde los acchivos que tengamos en el disco o desde el streaming de varios sitios. Otra buena opcion que tiene es la de las listas de...
Comandos de Unix VerTabla de los comandos principales de UNIX Comandos de Unix Descripción Opciones ls Muestra las listas de los contenidos de un directorio -a Muestra todos los archivos, incluyendo los archivos...
Tablas VerUso de las tablas A menudo resulta útil presentar información de una manera más estructurada que en las listas. Las tablas permiten mostrar esta información en filas y columnas. Las tablas se definen como series de filas. Una tabla debe respetar las...
Listas de correo VerEl concepto de listas de correo La lista de correo es uno de los servicios más usados en Internet, ya que permite que las personas envíen mensajes a uno o más receptores. El correo electrónico fue inventado por Ray Tomlinson en 1972. ...