Skip to content

Commit

Permalink
Triển khai bst khái quát với khóa kiểu chuỗi
Browse files Browse the repository at this point in the history
  • Loading branch information
bangoc committed Jan 5, 2025
1 parent 15d3a22 commit 06f172b
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 2 deletions.
3 changes: 2 additions & 1 deletion v3/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ add_test(NAME binsearch_ut COMMAND binsearch_ut)
add_test(NAME hmap_demo_ut COMMAND hmap_demo_ut)
add_test(NAME ivec_sort_ut COMMAND ivec_sort_ut)
add_test(NAME ivec_put_rem_demo_ut COMMAND ivec_put_rem_demo_ut)
add_test(NAME slist_demo_ut COMMAND slist_demo_ut)
add_test(NAME slist_demo_ut COMMAND slist_demo_ut)
add_test(NAME bst_demo_ut COMMAND bst_demo_ut)
229 changes: 229 additions & 0 deletions v3/bst.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
#ifndef BST_H_
#define BST_H_

/* (C) Nguyễn Bá Ngọc 2024 */

const static char k_bst_version[] = "3.0.0";

#include <stdlib.h>
#include <string.h>

#define BST_DECL(bst, value_t) \
struct bst##_node; \
struct bst; \
struct bst##_node *bst##_node(const char *key, value_t value); \
struct bst *bst(); \
struct bst##_node *bst##_put(struct bst *t, const char *key, value_t value); \
struct bst##_node *bst##_first(struct bst *t); \
struct bst##_node *bst##_next(struct bst##_node *n); \
struct bst##_node *bst##_search(struct bst *t, const char *key); \
int bst##_rem(struct bst *t, const char *key); \
void bst##_del(struct bst *t);

#define BST_IMPL(bst, key_size, value_t) \
struct bst##_node { \
char key[key_size]; \
value_t value; \
struct bst##_node *left, *right, *top; \
}; \
\
struct bst { \
struct bst##_node *root; \
int (*cmp)(const char *, const char *); \
long size; \
}; \
\
struct bst##_node *bst##_node(const char *key, value_t value) { \
struct bst##_node *nn = malloc(sizeof(struct bst##_node)); \
strcpy(nn->key, key); \
nn->value = value; \
nn->left = nn->right = nn->top = NULL; \
return nn; \
} \
\
struct bst *bst() { \
struct bst *t = malloc(sizeof (struct bst)); \
t->root = NULL; \
t->cmp = strcmp; \
t->size = 0; \
return t; \
} \
\
struct bst##_node *bst##_put(struct bst *t, const char *key, value_t value) { \
struct bst##_node *top = NULL, *n = t->root; \
int order; \
while (n) { \
order = t->cmp(key, n->key); \
if (order == 0) { \
return n; \
} \
top = n; \
n = order < 0? n->left: n->right; \
} \
n = bst##_node(key, value); \
n->top = top; \
++t->size; \
if (top == NULL) { \
t->root = n; \
return NULL; \
} \
if (order < 0) { \
top->left = n; \
} else { \
top->right = n; \
} \
return NULL; \
} \
\
static inline struct bst##_node *bst##_left_most(struct bst##_node *n) { \
struct bst##_node *top = NULL; \
while (n) { \
top = n; \
n = n->left; \
} \
return top; \
}\
struct bst##_node *bst##_first(struct bst *t) { \
return bst##_left_most(t->root); \
} \
\
struct bst##_node *bst##_next(struct bst##_node *n) { \
if (n->right) { \
return bst##_left_most(n->right); \
} \
while (n->top) { \
if (n->top->left == n) { \
return n->top; \
} \
n = n->top; \
} \
return NULL; \
} \
\
struct bst##_node *bst##_search(struct bst *t, const char *key) { \
struct bst##_node *n = t->root; \
while (n) { \
int o = t->cmp(key, n->key); \
if (o == 0) { \
return n; \
} \
n = o < 0? n->left: n->right; \
} \
return NULL; \
} \
\
static inline void bst##_change(struct bst *t, struct bst##_node *old, struct bst##_node *nn) { \
struct bst##_node *top = old->top; \
if (top == NULL) { \
t->root = nn; \
} else { \
if (top->left == old) { \
top->left = nn; \
} else { \
top->right = nn; \
} \
} \
if (nn) { \
nn->top = top; \
} \
} \
\
int bst##_rem(struct bst *t, const char *key) { \
struct bst##_node *n = bst##_search(t, key); \
if (!n) { \
return 0; \
} \
if (n->left == NULL && n->right == NULL) { \
/* TH1:
(n)
/ \
NULL NULL
*/ \
bst##_change(t, n, NULL); \
free(n); \
return 1; \
} \
struct bst##_node *r = n->right, *l = n->left; \
if (l == NULL) { \
/* TH2:
(n)
/ \
NULL r
*/ \
bst##_change(t, n, r); \
free(n); \
return 1; \
} \
if (r == NULL) { \
/* TH2:
(n)
/ \
l NULL
*/ \
bst##_change(t, n, l); \
free(n); \
return 1; \
} \
if (r->left == NULL) { \
/* TH3:
(n)
/ \
(x) r
/ \
NULL (y)
*/ \
r->left = n->left; \
n->left->top = r; \
bst##_change(t, n, r); \
free(n); \
return 1; \
} \
/* TH4:
(n)
/ \
(x) r
/ \
nn (y)
/ \
NULL (z)
*/ \
struct bst##_node *nn = r->left, *nnt = r; \
while (nn->left) { \
nnt = nn; \
nn = nn->left; \
} \
nnt->left = nn->right; \
if (nn->right) { \
nn->right->top = nnt; \
} \
nn->left = l; \
nn->right = r; \
l->top = nn; \
r->top = nn; \
bst##_change(t, n, nn); \
free(n); \
return 1; \
} \
\
static void bst##_del_recursive(struct bst##_node *n) { \
if (n->left) { \
bst##_del_recursive(n->left); \
} \
if (n->right) { \
bst##_del_recursive(n->right); \
} \
free(n); \
} \
\
void bst##_del(struct bst *t) { \
if (t->root) { \
bst##_del_recursive(t->root); \
} \
free(t); \
}

#define BST_DECL_IMPL(struct_name, key_size, value_t) \
BST_DECL(struct_name, value_t) \
BST_IMPL(struct_name, key_size, value_t)

#endif // BST_H_
38 changes: 38 additions & 0 deletions v3/demo/bst_word_demo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "bst.h"

#include <stdio.h>
#include <string.h>

BST_DECL_IMPL(bst, 32, int)

int main() {
struct bst *t = bst();
char cmd[32], word[32];
while (scanf("%s", cmd) == 1) {
if (strcmp(cmd, "print") == 0) {
printf("Traverse: \n");
for (struct bst_node *n = bst_first(t); n; n = bst_next(n)) {
printf("%s: %d\n", n->key, n->value);
}
continue;
}
scanf("%s", word);
if (strcmp(cmd, "insert") == 0) {
struct bst_node *n = bst_put(t, word, 1);
if (n) {
++n->value;
printf("freq(%s) updated = %d\n", word, n->value);
} else {
printf("Inserted %s\n", word);
}
} else if (strcmp(cmd, "freq") == 0) {
struct bst_node *n = bst_search(t, word);
printf("freq(%s) = %d\n", word, n? n->value: 0);
} else if (strcmp(cmd, "rem") == 0) {
if (bst_rem(t, word)) {
printf("Deleted %s\n", word);
}
}
}
bst_del(t);
}
12 changes: 12 additions & 0 deletions v3/demo/words.inp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
insert aaa
insert bbb
insert aaa
insert ccc
freq bbb
freq aaa
print
rem aaa
print
freq aaa
insert aaa
print
4 changes: 3 additions & 1 deletion v3/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ add_executable(binsearch_ut binsearch_ut.c)
add_executable(hmap_demo_ut hmap_demo_ut.c)
add_executable(ivec_sort_ut ivec_sort_ut.c)
add_executable(ivec_put_rem_demo_ut ivec_put_rem_demo_ut.c)
add_executable(slist_demo_ut slist_demo_ut.c)
add_executable(slist_demo_ut slist_demo_ut.c)
add_executable(tmap_demo_ut tmap_demo_ut.c)
add_executable(bst_demo_ut bst_demo_ut.c)

0 comments on commit 06f172b

Please sign in to comment.