This commit is contained in:
2026-05-17 21:12:22 -06:00
commit b4d6de4fe2
5 changed files with 566 additions and 0 deletions

60
.gitignore vendored Normal file
View File

@@ -0,0 +1,60 @@
# Directories
build/
build-*/
cmake-build-*/
.cache/
out/
out/Debug/
out/Release/
# Cmake files
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
CTestTestfile.cmake
Testing/
compile_commands.json
../compile_commands.json
build/compile_commands.json
cmake
# Make / Ninja
Makefile
*.ninja
*.ninja_deps
*.ninja_log
rules.ninja
# Object files
*.o
*.obj
*.lo
*.la
# Binaries
*.out
*.exe
*.dll
*.so
*.so.*
*.dylib
*.a
# Debug / Sanitizer
*.dSYM/
*.gcno
*.gcda
*.gcov
# Editors
.vscode/
.idea/
*.swp
*.swo
*~
# Git
COMMIT_MESSAGE
docs
docs/images

60
CMakeLists.txt Normal file
View File

@@ -0,0 +1,60 @@
cmake_minimum_required(VERSION 3.20)
project(avl VERSION 1.0 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Opciones
option(AVL_BUILD_TESTS "Build avl tests" OFF)
option(AVL_ENABLE_SANITIZERS "Enable sanitizers" ON)
# ------------------------
# Library
# ------------------------
add_library(avl
src/avl.c
)
target_include_directories(avl
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_compile_options(avl PRIVATE
-Wall
-Wextra
-Wpedantic
)
# ------------------------
# Example
# ------------------------
add_executable(avl_example src/main.c)
target_link_libraries(avl_example
avl
)
# ------------------------
# Sanitizers (debug only)
# ------------------------
if(AVL_ENABLE_SANITIZERS)
target_compile_options(avl_example PRIVATE
-fsanitize=address,undefined
)
target_link_options(avl_example PRIVATE
-fsanitize=address,undefined
)
endif()
# ------------------------
# Testing
# ------------------------
if(AVL_BUILD_TESTS)
enable_testing()
add_subdirectory(test)
endif()

38
include/avl.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef AVL_H
#define AVL_H
#include <stddef.h>
typedef struct AVLTree AVLTree;
typedef struct AVLNode AVLNode;
typedef enum {
AVL_OK,
AVL_BAD_ALLOC,
AVL_NULL_ARG,
AVL_DUPLICATE,
AVL_EMPTY,
} AvlErr;
typedef enum {
AVL_ROT_NONE,
AVL_ROT_LEFT,
AVL_ROT_RIGHT,
AVL_ROT_LEFT_RIGHT,
AVL_ROT_RIGHT_LEFT,
} AvlRotation;
AVLTree *avl_create(void);
AvlErr avl_destroy(AVLTree **tree);
AvlErr avl_insert(AVLTree *tree, int key);
AvlErr avl_node_count(AVLTree *tree, size_t *out);
AvlErr avl_height(AVLTree *tree, int *out);
void avl_print(AVLTree *tree);
void avl_print_inorder(AVLTree *tree);
const char *avl_rotation_name(AvlRotation rot);
const char *avl_err_name(AvlErr err);
#endif /* AVL_H */

287
src/avl.c Normal file
View File

@@ -0,0 +1,287 @@
#include "avl.h"
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
struct AVLNode {
int key;
int height;
AVLNode *left;
AVLNode *right;
};
struct AVLTree {
AVLNode *root;
size_t count;
};
static int node_height(AVLNode *node) {
return node == NULL ? -1 : node->height;
}
static int node_balance(AVLNode *node) {
if (node == NULL) {
return 0;
}
return node_height(node->left) - node_height(node->right);
}
static int max_int(int a, int b) {
return a > b ? a : b;
}
static void node_update_height(AVLNode *node) {
node->height = 1 + max_int(node_height(node->left),
node_height(node->right));
}
static AVLNode *node_create(int key) {
AVLNode *node = malloc(sizeof(AVLNode));
if (node == NULL) {
return NULL;
}
node->key = key;
node->height = 0;
node->left = NULL;
node->right = NULL;
return node;
}
static void node_destroy_recursive(AVLNode *node) {
if (node == NULL) {
return;
}
node_destroy_recursive(node->left);
node_destroy_recursive(node->right);
free(node);
}
static AVLNode *rotate_right(AVLNode *y) {
printf(" [Rotacion] Simple derecha (LL) en nodo %d\n", y->key);
AVLNode *x = y->left;
AVLNode *t2 = x->right;
x->right = y;
y->left = t2;
node_update_height(y);
node_update_height(x);
return x;
}
static AVLNode *rotate_left(AVLNode *x) {
printf(" [Rotacion] Simple izquierda (RR) en nodo %d\n", x->key);
AVLNode *y = x->right;
AVLNode *t2 = y->left;
y->left = x;
x->right = t2;
node_update_height(x);
node_update_height(y);
return y;
}
static AVLNode *rotate_left_right(AVLNode *z) {
printf(" [Rotacion] Doble izquierda-derecha (LR) en nodo %d\n", z->key);
z->left = rotate_left(z->left);
return rotate_right(z);
}
static AVLNode *rotate_right_left(AVLNode *z) {
printf(" [Rotacion] Doble derecha-izquierda (RL) en nodo %d\n", z->key);
z->right = rotate_right(z->right);
return rotate_left(z);
}
static AVLNode *node_insert(AVLNode *node, int key, AvlErr *err) {
if (node == NULL) {
AVLNode *new_node = node_create(key);
if (new_node == NULL) {
*err = AVL_BAD_ALLOC;
}
return new_node;
}
if (key < node->key) {
node->left = node_insert(node->left, key, err);
} else if (key > node->key) {
node->right = node_insert(node->right, key, err);
} else {
*err = AVL_DUPLICATE;
return node;
}
if (*err != AVL_OK) {
return node;
}
node_update_height(node);
int balance = node_balance(node);
if (balance > 1 && key < node->left->key) {
return rotate_right(node);
}
if (balance < -1 && key > node->right->key) {
return rotate_left(node);
}
if (balance > 1 && key > node->left->key) {
return rotate_left_right(node);
}
if (balance < -1 && key < node->right->key) {
return rotate_right_left(node);
}
return node;
}
static void node_print_inorder(AVLNode *node) {
if (node == NULL) {
return;
}
node_print_inorder(node->left);
printf("%d ", node->key);
node_print_inorder(node->right);
}
static void node_print_visual(AVLNode *node, int level) {
if (node == NULL) {
return;
}
node_print_visual(node->right, level + 1);
for (int i = 0; i < level; i++) {
printf(" ");
}
printf("[%d] (h=%d, bf=%d)\n",
node->key,
node->height,
node_balance(node));
node_print_visual(node->left, level + 1);
}
AVLTree *avl_create(void) {
AVLTree *tree = malloc(sizeof(AVLTree));
if (tree == NULL) {
return NULL;
}
tree->root = NULL;
tree->count = 0;
return tree;
}
AvlErr avl_destroy(AVLTree **tree) {
if (tree == NULL || *tree == NULL) {
return AVL_NULL_ARG;
}
node_destroy_recursive((*tree)->root);
free(*tree);
*tree = NULL;
return AVL_OK;
}
AvlErr avl_insert(AVLTree *tree, int key) {
if (tree == NULL) {
return AVL_NULL_ARG;
}
AvlErr err = AVL_OK;
tree->root = node_insert(tree->root, key, &err);
if (err == AVL_OK) {
tree->count++;
}
return err;
}
AvlErr avl_node_count(AVLTree *tree, size_t *out) {
if (tree == NULL || out == NULL) {
return AVL_NULL_ARG;
}
*out = tree->count;
return AVL_OK;
}
AvlErr avl_height(AVLTree *tree, int *out) {
if (tree == NULL || out == NULL) {
return AVL_NULL_ARG;
}
*out = node_height(tree->root);
return AVL_OK;
}
void avl_print(AVLTree *tree) {
if (tree == NULL) {
return;
}
printf("AVLTree {\n");
if (tree->root == NULL) {
printf(" (vacio)\n");
} else {
node_print_visual(tree->root, 1);
}
printf("}\n");
printf("Nodos: %zu | Altura: %d\n",
tree->count,
node_height(tree->root));
}
void avl_print_inorder(AVLTree *tree) {
if (tree == NULL) {
return;
}
printf("Inorden: [ ");
node_print_inorder(tree->root);
printf("]\n");
}
const char *avl_rotation_name(AvlRotation rot) {
switch (rot) {
case AVL_ROT_NONE: return "Ninguna";
case AVL_ROT_LEFT: return "Simple izquierda (RR)";
case AVL_ROT_RIGHT: return "Simple derecha (LL)";
case AVL_ROT_LEFT_RIGHT: return "Doble izquierda-derecha (LR)";
case AVL_ROT_RIGHT_LEFT: return "Doble derecha-izquierda (RL)";
default: return "Desconocida";
}
}
const char *avl_err_name(AvlErr err) {
switch (err) {
case AVL_OK: return "AVL_OK";
case AVL_BAD_ALLOC: return "AVL_BAD_ALLOC";
case AVL_NULL_ARG: return "AVL_NULL_ARG";
case AVL_DUPLICATE: return "AVL_DUPLICATE";
case AVL_EMPTY: return "AVL_EMPTY";
default: return "Desconocido";
}
}

121
src/main.c Normal file
View File

@@ -0,0 +1,121 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "avl.h"
static void print_separator(void) {
printf("--------------------------------------------------\n");
}
static void print_menu(void) {
print_separator();
printf(" Arbol AVL Menu\n");
print_separator();
printf(" 1. Insertar numero\n");
printf(" 2. Imprimir arbol (visual)\n");
printf(" 3. Imprimir recorrido inorden\n");
printf(" 4. Salir\n");
print_separator();
printf(" Opcion: ");
}
static int read_int(int *out) {
char buf[64];
if (fgets(buf, sizeof(buf), stdin) == NULL) {
return -1;
}
char *endptr;
long val = strtol(buf, &endptr, 10);
if (endptr == buf || (*endptr != '\n' && *endptr != '\0')) {
return -1;
}
*out = (int)val;
return 0;
}
int main(void) {
AVLTree *tree = avl_create();
if (tree == NULL) {
fprintf(stderr, "Error: no se pudo crear el arbol AVL.\n");
return EXIT_FAILURE;
}
printf("\n Bienvenido al programa de Arbol AVL\n");
printf(" Las rotaciones se imprimiran automaticamente al insertar.\n\n");
int running = 1;
while (running) {
print_menu();
int choice;
if (read_int(&choice) != 0) {
printf(" Entrada invalida. Intente de nuevo.\n\n");
continue;
}
switch (choice) {
case 1: {
printf(" Ingrese el numero a insertar: ");
int key;
if (read_int(&key) != 0) {
printf(" Entrada invalida.\n\n");
break;
}
AvlErr err = avl_insert(tree, key);
switch (err) {
case AVL_OK:
printf(" Numero %d insertado correctamente.\n\n", key);
break;
case AVL_DUPLICATE:
printf(" El numero %d ya existe en el arbol.\n\n", key);
break;
case AVL_BAD_ALLOC:
fprintf(stderr, " Error: fallo de memoria.\n\n");
break;
default:
fprintf(stderr, " Error inesperado: %s\n\n",
avl_err_name(err));
break;
}
break;
}
case 2: {
printf("\n");
avl_print(tree);
printf("\n");
printf(" Leyenda (vista 90 grados contra las manecillas):\n");
printf(" Subárbol derecho aparece arriba, izquierdo abajo.\n");
printf(" h=altura del nodo | bf=factor de balance\n\n");
break;
}
case 3: {
printf("\n");
avl_print_inorder(tree);
printf("\n");
break;
}
/* ---- Exit ---- */
case 4: {
running = 0;
break;
}
default: {
printf(" Opcion no valida. Elija entre 1 y 4.\n\n");
break;
}
}
}
avl_destroy(&tree);
printf("\n Arbol destruido. Hasta luego.\n\n");
return EXIT_SUCCESS;
}