ALL
This commit is contained in:
60
.gitignore
vendored
Normal file
60
.gitignore
vendored
Normal 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
60
CMakeLists.txt
Normal 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
38
include/avl.h
Normal 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
287
src/avl.c
Normal 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
121
src/main.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user