Estructuras de datos

Tipos abstractos de datos

Tipos de datos

Un tipo de dato es un atributo asociado a una pieza de información que le dice a la computadora como debe interpretar el valor contenido

 

Algunos ejemplos de tipos de datos son:

  • números enteros
  • números flotantes
  • caracteres
  • valores booleanos
  • enumerables
  • arreglos
  • cadenas

Tipos de datos

En términos generales, podemos dividir los tipos de datos en:

  • primitivos
  • abstractos

Son todos aquellos que se encuentran directamente implementados y soportados por un lenguaje de programación (y, en última instancia, por la arquitectura de una computadora)

 

Son eficientes pero muy limitados en la complejidad de información que pueden manipular

Tipos de datos primitivos

Son un marco conceptual para definir estructuras de datos con base en sus operaciones y que no revelan los detalles de su implementación encapsulando su funcionamiento

 

Pueden utilizar tipos de datos primitivos o abstractos

 

Algunos ejempos son las pilas, colas, listas, los árboles, grafos y diccionarios aunque también depende del lenguaje de programación

 

Se usan para manipular información compleja o para mejorar las capacidades de un lenguaje de programación

Tipos de datos abstractos

Una pila es una estructura lineal que sigue el principio LIFO (last in, first out): sólo se puede agregar un elemento en el tope de la pila y sólo se puede tomar (o eliminar) el último elemento que se agregó a la pila

Pilas

100

tope

Una pila es una estructura lineal que sigue el principio LIFO (last in, first out): sólo se puede agregar un elemento en el tope de la pila y sólo se puede tomar (o eliminar) el último elemento que se agregó a la pila

Pilas

100
350
100

tope

Una pila es una estructura lineal que sigue el principio LIFO (last in, first out): sólo se puede agregar un elemento en el tope de la pila y sólo se puede tomar (o eliminar) el último elemento que se agregó a la pila

Pilas

100
350
100
525
350
100

tope

Una pila es una estructura lineal que sigue el principio LIFO (last in, first out): sólo se puede agregar un elemento en el tope de la pila y sólo se puede tomar (o eliminar) el último elemento que se agregó a la pila

Pilas

100
350
100
525
350
100
350
100

tope

La implementación en C de una pila estática depende de dos cosas:

  1. Una estructura de datos que contenga una referencia a un arreglo para guardar los elementos de la pila y una referencia al tope de la pila
  2. Cinco funciones para manipular la pila

Pilas

La estructura de datos para una pila estática que sólo almacena números enteros es algo así:

Pilas

#include <stdio.h>
#include <stdbool.h>

//Tamaño máximo de la pila
#define MAX 100

//La estructura que describe la pila
typedef struct {
    int arreglo[MAX];  
    int tope;        
} Pila;


//Función para inicializar una pila
void initialize(Pila *pila) {
    pila->tope = -1;  
}


int main() {
    Pila pila;

    initialize(&pila);  

    return 0;
}

Mientras que las operaciones son:

  • push(pila, valor) para agregar valor en pila
  • pop(pila) para remover el último elemento de pila y regresarlo
  • top(pila) para regresar el último elemento agregado en pila
  • isEmpty(pila) para saber si pila está vacía
  • isFull(pila) para saber si pila está llena

Pilas

¿Cómo creen que deberían implementarse esas funciones?

#include <stdio.h>
#include <stdbool.h>

#define MAX 100
#define ERROR_OVERFLOW -1
#define ERROR_UNDERFLOW -2
#define ERROR_EMPTY -3
#define ERROR_FULL -4

//Definición de una estructura para la Pila
typedef struct {
	int arreglo[MAX];
	int tope;
} Pila;

//Función para inicializar una Pila
void initialize(Pila *p) {
	p->tope = -1;
}

//Función para determinar si una Pila está vacía
bool isEmpty(Pila *p) {
	return p->tope == -1;
}

//Función para determinar si una Pila está llena
bool isFull(Pila *p) {
	return p->tope == MAX - 1;
}

//Función para agregar un elemento nuevo a la Pila
void push(Pila *p, int valor) {
	if (isFull(p)) {
		printf("La pila está llena\n");
	}
	else {
		p->tope = p->tope + 1;
		p->arreglo[p->tope] = valor;
		printf("Se agregó el valor %d a la pila\n", valor);
	}
}

//Función para remover un elemento de una Pila
int pop(Pila *p) {
	if (isEmpty(p)) {
		printf("La pila está vacía\n");
		return ERROR_UNDERFLOW;
	}
	else {
		int removido = p->arreglo[p->tope];
		p->tope -= 1;
		printf("Removí %d de la pila\n", removido);
		return removido;
	}
}

//Función para ver el elemento superior de la Pila
int top(Pila *p) {
	if (isEmpty(p)) {
		printf("La Pila está vacía\n");
		return ERROR_EMPTY;
	}
	return p->arreglo[p->tope];
}

int main() {
	Pila p;
	int v;
	int superior;

	initialize(&p);

	push(&p, 10);
	push(&p, 4);
	push(&p, 13);
	push(&p, 5);

	while(!isEmpty(&p)) {
		superior = pop(&p);
	}


	return 0;
}

Y acá tienen una implementación como ejemplo...

// C Program to demonstrate how to Implement a Stack
#include <stdio.h>
#include <stdbool.h>

// Define the maximim capacity of the stack
#define MAX_SIZE 100

// Define a structure for the stack
typedef struct {
    // Array to store stack elements
    int arr[MAX_SIZE];  
    // Index of the top element in the stack
    int top;        
} Stack;

// Function to initialize the stack
void initialize(Stack *stack) {
    // Set top index to -1 to indicate an empty stack
    stack->top = -1;  
}

// Function to check if the stack is empty
bool isEmpty(Stack *stack) {
    // If top is -1, the stack is empty
    return stack->top == -1;  
}

// Function to check if the stack is full
bool isFull(Stack *stack) {
    // If top is MAX_SIZE - 1, the stack is full
    return stack->top == MAX_SIZE - 1;  
}

// Function to push an element onto the stack
void push(Stack *stack, int value) {
    // Check for stack overflow
    if (isFull(stack)) {
        printf("Stack Overflow\n");
        return;
    }
    // Increment top and add the value to the top of the stack
    stack->arr[++stack->top] = value;
    printf("Pushed %d onto the stack\n", value);
}

// Function to pop an element from the stack
int pop(Stack *stack) {
    // Check for stack underflow
    if (isEmpty(stack)) {
        printf("Stack Underflow\n");
        return -1;
    }
    // Return the top element 
    int popped = stack->arr[stack->top];
    // decrement top pointer
    stack->top--;
    printf("Popped %d from the stack\n", popped);
    // return the popped element
    return popped;
}

// Function to peek the top element of the stack
int peek(Stack *stack) {
    // Check if the stack is empty
    if (isEmpty(stack)) {
        printf("Stack is empty\n");
        return -1;
    }
    // Return the top element without removing it
    return stack->arr[stack->top];
}

int main() {
    Stack stack;
    // Initialize the stack
    initialize(&stack);  

    // Push elements onto the stack and print the stack after each push
    push(&stack, 3);
    printf("Top element: %d\n", peek(&stack));

    push(&stack, 5);
    printf("Top element: %d\n", peek(&stack));

    push(&stack, 2);
    printf("Top element: %d\n", peek(&stack));

    push(&stack, 8);
    printf("Top element: %d\n", peek(&stack));

    // Pop elements from the stack and print the stack after each pop
    while (!isEmpty(&stack)) {
        printf("Top element: %d\n", peek(&stack));
        printf("Popped element: %d\n", pop(&stack));
    }

    return 0;
}

Fuentes:

Código

Tutorial

Estructuras de datos: Estructuras de datos

By Gilberto 🦁

Estructuras de datos: Estructuras de datos

Estructuras de datos

  • 160