From 8c2e98eb9b702a948a3d25b35bcbb10ac7f67bc8 Mon Sep 17 00:00:00 2001 From: Nguyen Ba Ngoc Date: Sat, 30 Dec 2023 21:51:09 +0700 Subject: [PATCH] =?UTF-8?q?Ti=E1=BA=BFp=20t=E1=BB=A5c=20c=E1=BA=ADp=20nh?= =?UTF-8?q?=E1=BA=ADt=20tmap=20&=20h=E1=BB=A3p=20nh=E1=BA=A5t=20cgen.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- all/cgen.h | 283 +++++++++++++++++++++++++++++++--------------------- cont/tmap.h | 189 +++++++++++------------------------ 2 files changed, 228 insertions(+), 244 deletions(-) diff --git a/all/cgen.h b/all/cgen.h index 93442eff..0ea77ae3 100644 --- a/all/cgen.h +++ b/all/cgen.h @@ -442,90 +442,128 @@ void prefix##free(struct tname *t); \ vtype *prefix##put(struct tname *t, ktype key, vtype value); \ vtype *prefix##get(struct tname *t, ktype key); \ struct tname *prefix##remove(struct tname *t, ktype key) -#define TSEARCH(t,key,x) \ -do { \ - int rl; \ - x = t->root; \ - while (x) { \ - rl = t->cmp(&key, &x->key); \ - if (rl == 0) { \ - break; \ +#define TIMPL(tname,ktype,vtype,prefix) \ +static inline void prefix##change(struct TNN(tname) *old_node, \ + struct TNN(tname) *new_node, struct tname *t) { \ + struct TNN(tname) *top = old_node->top; \ + if (top) { \ + if (top->left == old_node) { \ + top->left = new_node; \ + } else { \ + top->right = new_node; \ } \ - x = rl < 0? x->left: x->right; \ + } else { \ + t->root = new_node; \ + } \ + if (new_node) { \ + (new_node)->top = top; \ } \ -} while (0) -#define TCHANGE(old_node,new_node,parent,t) \ - do { \ - if (parent) { \ - if (parent->left == old_node) { \ - parent->left = new_node; \ +} \ + \ +static inline void prefix##rotate_left(struct tname *t, struct TNN(tname) *x) { \ + struct TNN(tname) *y = x->right; \ + x->right = y->left; \ + if (y->left != NULL) { \ + y->left->top = x; \ + } \ + prefix##change(x, y, t); \ + y->left = x; \ + x->top = y; \ +}\ + \ +static inline void prefix##rotate_right(struct tname *t, struct TNN(tname) *x) { \ + struct TNN(tname) *y = x->left; \ + x->left = y->right; \ + if (y->right != NULL) { \ + y->right->top = x; \ + } \ + prefix##change(x, y, t); \ + y->right = x; \ + x->top = y; \ +}\ +static inline void prefix##put_fixup(struct tname *t, struct TNN(tname) *n) {\ + \ + struct TNN(tname) *p = n->top, *pp = p->top; \ + \ + while (1) { \ + if (p == pp->left) { \ + if (TIS_RED(pp->right)) { \ + \ + TPAINT_BLACK(p); \ + TPAINT_BLACK(pp->right); \ + TPAINT_RED(pp); \ + n = pp; \ + p = n->top; \ + if (p == NULL) { \ + \ + TPAINT_BLACK(n); \ + break; \ + } \ + pp = p->top; \ + if (TIS_BLACK(p)) { \ + \ + break; \ + } \ } else { \ - parent->right = new_node; \ + if (n == p->right) { \ + \ + prefix##rotate_## left(t, p); \ + n = p; \ + p = n->top; \ + } \ + \ + TPAINT_BLACK(p); \ + TPAINT_RED(pp); \ + prefix##rotate_## right(t, pp); \ + break; \ } \ } else { \ - t->root = new_node; \ - } \ - } while (0) -#define TROTATE(t,x,right,left,y_) \ - do { \ - y_ = (x)->right; \ - (x)->right = y_->left; \ - if (y_->left != NULL) { \ - y_->left->top = (x); \ - } \ - y_->top = (x)->top; \ - TCHANGE(x, y_, (x)->top, t); \ - y_->left = (x); \ - (x)->top = y_; \ - } while (0) -#define IMPL_INSERT_FIXUP(t,n,p,left,right,y_) \ - if (TIS_RED(p->top->right)) { \ + \ + if (TIS_RED(pp->left)) { \ \ TPAINT_BLACK(p); \ - TPAINT_BLACK(p->top->right); \ - TPAINT_RED(p->top); \ - n = p->top; \ + TPAINT_BLACK(pp->left); \ + TPAINT_RED(pp); \ + n = pp; \ p = n->top; \ if (p == NULL) { \ \ TPAINT_BLACK(n); \ break; \ } \ + pp = p->top; \ if (TIS_BLACK(p)) { \ \ break; \ } \ } else { \ - if (n == n->top->right) { \ + if (n == p->left) { \ \ - TROTATE(t, p, right, left, y_); \ + prefix##rotate_## right(t, p); \ n = p; \ p = n->top; \ + pp = p->top; \ } \ \ TPAINT_BLACK(p); \ - TPAINT_RED(p->top); \ - p = p->top; \ - TROTATE(t, p, left, right, y_); \ + TPAINT_RED(pp); \ + prefix##rotate_## left(t, pp); \ break; \ - } -#define TPUT_FIXUP(t,n,p,y_) \ -do { \ - \ - while (1) { \ - \ - if (p == p->top->left) { \ - IMPL_INSERT_FIXUP(t, n, p, left, right, y_) \ - } else { \ - IMPL_INSERT_FIXUP(t, n, p, right, left, y_) \ + } \ } \ } \ -} while (0) -#define ERASE_COLOR_SYMMETRY(left,right,p,n,s,cn,dn,u_) \ - \ +}\ +static inline void prefix##delete_fixup(struct tname *t, struct TNN(tname)* p) {\ + \ + struct TNN(tname) *n = NULL, *s, *dn, *cn; \ + \ + \ + while (1) { \ + s = p->right; \ + if (n != s) { \ if (TIS_RED(s)) { \ \ - TROTATE(t, p, right, left, u_); \ + prefix##rotate_## left(t, p); \ TPAINT_RED(p); \ TPAINT_BLACK(s); \ s = p->right; \ @@ -548,32 +586,53 @@ do { \ break; \ } \ \ - TROTATE(t, s, left, right, u_); \ + prefix##rotate_## right(t, s); \ s = p->right; \ } \ \ dn = s->right; \ - TROTATE(t, p, right, left, u_); \ + prefix##rotate_ ##left(t, p); \ TPAINT(s, p->color); \ TPAINT_BLACK(p); \ TPAINT_BLACK(dn); \ - break -#define TDELETE_FIXUP(t,p,n,s,cn,dn,u_) \ -do { \ - \ - n = NULL; \ - while (1) { \ - \ - s = p->right; \ - if (n != s) { \ - ERASE_COLOR_SYMMETRY(left, right, p, n, s, cn, dn, u_); \ + break; \ } else { \ + \ s = p->left; \ - ERASE_COLOR_SYMMETRY(right, left, p, n, s, cn, dn, u_); \ + if (TIS_RED(s)) { \ + prefix##rotate_## right(t, p); \ + TPAINT_RED(p); \ + TPAINT_BLACK(s); \ + s = p->left; \ + } \ + dn = s->left; \ + if (TIS_BLACK(dn)) { \ + cn = s->right; \ + if (TIS_BLACK(cn)) { \ + TPAINT_RED(s); \ + if (TIS_RED(p)) { \ + TPAINT_BLACK(p); \ + } else { \ + n = p; \ + p = n->top; \ + if (p) { \ + continue; \ + } \ + } \ + break; \ + } \ + prefix##rotate_## left(t, s); \ + s = p->left; \ + } \ + dn = s->left; \ + prefix##rotate_ ##right(t, p); \ + TPAINT(s, p->color); \ + TPAINT_BLACK(p); \ + TPAINT_BLACK(dn); \ + break; \ } \ } \ -} while (0) -#define TIMPL(tname,ktype,vtype,prefix) \ +}\ struct TNN(tname) *TNN(tname)(ktype key, vtype value) { \ struct TNN(tname) *nn = malloc(sizeof(struct TNN(tname))); \ nn->key = key; \ @@ -636,17 +695,16 @@ struct TNN(tname) *prefix##prev_lnr(struct TNN(tname) *n) { \ return top; \ } \ struct TNN(tname) *prefix##first_lrn(struct tname *t) { \ - return prefix##left_deepest(t->root); \ + return t->root? prefix##left_deepest(t->root): NULL; \ } \ struct TNN(tname) *prefix##first_lnr(struct tname *t) { \ - return prefix##left_most(t->root); \ + return t->root? prefix##left_most(t->root): NULL; \ } \ struct TNN(tname) *prefix##last_lnr(struct tname *t) { \ - return prefix##right_most(t->root); \ + return t->root? prefix##right_most(t->root): NULL; \ } \ struct TNN(tname) *prefix##pval_node(void *pv) { \ - void *tmp = pv; \ - return tmp - offsetof(struct TNN(tname), value); \ + return pv? pv - offsetof(struct TNN(tname), value): NULL; \ } \ struct tname *prefix##create(compare_fnt cmp) { \ if (!cmp) { \ @@ -692,72 +750,62 @@ static struct tname *prefix##delete(struct tname *t, struct TNN(tname) *dn) { \ struct TNN(tname) *node = dn; \ struct TNN(tname) *child = node->right, \ *tmp = node->left, \ - *parent, *rebalance; \ - struct TNN(tname) *p; \ - enum tcolors c; \ + *top, *rebalance; \ + \ if (!tmp) { \ - \ - p = node->top; \ - c = node->color; \ - parent = p; \ - TCHANGE(node, child, parent, t); \ + prefix##change(node, child, t); \ if (child) { \ - TSET_PC(child, p, c); \ + \ + TPAINT_BLACK(child); \ rebalance = NULL; \ } else { \ - rebalance = c == BLACK? parent: NULL; \ + rebalance = TIS_BLACK(node)? node->top: NULL; \ } \ - tmp = parent; \ } else if (!child) { \ - \ - p = node->top; \ - c = node->color; \ - TSET_PC(tmp, p, c); \ - parent = p; \ - TCHANGE(node, tmp, parent, t); \ + \ + prefix##change(node, tmp, t); \ + TPAINT_BLACK(tmp); \ rebalance = NULL; \ - tmp = parent; \ } else { \ struct TNN(tname) *successor = child, *child2; \ tmp = child->left; \ if (!tmp) { \ \ - parent = successor; \ + top = successor; \ child2 = successor->right; \ } else { \ \ do { \ - parent = successor; \ successor = tmp; \ tmp = tmp->left; \ } while (tmp); \ + top = successor->top; \ child2 = successor->right; \ - parent->left = child2; \ + top->left = child2; \ + if (child2) { \ + child2->top = top; \ + } \ successor->right = child; \ child->top = successor; \ } \ + \ tmp = node->left; \ successor->left = tmp; \ tmp->top = successor; \ - p = node->top; \ - c = node->color; \ - tmp = p; \ - TCHANGE(node, successor, tmp, t); \ if (child2) { \ - TSET_PC(child2, parent, BLACK); \ + TPAINT_BLACK(child2); \ rebalance = NULL; \ - } else { \ - enum tcolors c2 = successor->color; \ - rebalance = c2 == BLACK? parent: NULL; \ - } \ - TSET_PC(successor, p, c); \ - tmp = successor; \ + } else {\ + rebalance = TIS_BLACK(successor) ? top: NULL; \ + }\ + prefix##change(node, successor, t); \ + TPAINT(successor, node->color); \ } \ if (rebalance) { \ - struct TNN(tname) *n, *s, *cn, *dn, *u_; \ - TDELETE_FIXUP(t, rebalance, n, s, cn, dn, u_); \ + prefix##delete_fixup(t, rebalance); \ } \ free(dn); \ + --(t->size); \ return t; \ } \ vtype *prefix##put(struct tname *t, ktype key, vtype value) { \ @@ -787,23 +835,27 @@ vtype *prefix##put(struct tname *t, ktype key, vtype value) { \ nn->color = BLACK; \ } else if (TIS_RED(top)) { \ \ - struct TNN(tname) *y_; \ - TPUT_FIXUP(t, nn, top, y_); \ + prefix##put_fixup(t, nn); \ } \ ++t->size; \ return NULL; \ } \ vtype *prefix##get(struct tname *t, ktype key) { \ - struct TNN(tname) *x; \ - TSEARCH(t, key, x); \ + struct TNN(tname) *x = t->root; \ + while (x) { \ + int rl = t->cmp(&key, &x->key); \ + if (rl == 0) { \ + break; \ + } \ + x = rl < 0? x->left: x->right; \ + } \ if (!x) { \ return NULL; \ } \ return &x->value; \ } \ struct tname *prefix##remove(struct tname *t, ktype key) { \ - struct TNN(tname) *n; \ - TSEARCH(t, key, n); \ + struct TNN(tname) *n = prefix##pval_node(prefix##get(t, key)); \ if (!n) { \ return NULL; \ } \ @@ -814,7 +866,6 @@ struct tname *prefix##remove(struct tname *t, ktype key) { \ t->fv(n->value); \ }\ prefix##delete(t, n);\ - --(t->size); \ return t; \ } #define TDECL_IMPL(tname,keytype,valtype,prefix) \ diff --git a/cont/tmap.h b/cont/tmap.h index 09ab1dc6..33f46408 100644 --- a/cont/tmap.h +++ b/cont/tmap.h @@ -245,131 +245,18 @@ static inline void prefix##delete_fixup(struct tname *t, struct TNN(tname)* p) { /* Trong các sơ đồ cây nút viết hoa là nút đen, * nút viết thường là nút đỏ, nút trong ngoặc có thể là đỏ hoặc đen. */ \ - /* Trường hợp 1.1 - Xoay trái ở p - * - * P S - * / \ / \ - * N s --> p DN - * / \ / \ - * CN DN N CN <- s mới - */ \ - /* - * Trường hợp 1.2 - Đảo mầu s, p có thể có mầu bất kỳ (có mầu đỏ - * sau khi xử lý trường hợp 1) - * - * (p) (p) - * / \ / \ - * N S --> N s - * / \ / \ - * CN DN CN DN - * - * Vi phạm ràng buộc 5 có thể được khắc phục bằng cách đảo mầu p - * thành đen nếu nó là nút đỏ, hoặc đệ quy tại p nếu ngược lại. - */ \ - /* - * Trường hợp 1.3 - Xoay phải tại s (p có thể có mầu bất kỳ) - * - * (p) (p) - * / \ / \ - * N S --> N cn - * / \ \ - * cn DN S - * \ - * DN - * Lưu ý: + p có thể là nút đỏ, và nếu như vậy thì cả p và - * cn đều là các nút đỏ sau khi xoay (vi phạm ràng buộc 4). - * - * + Đường đi từ p qua cn sau đó rẽ về phía N bị giảm 1 - * nút đen (S, vi phạm tính chất 5). - * - * Các vấn đề này được xử lý trong trường hợp 4: Sau khi - * xoay phải tại p, cn được tô bằng mầu của p, dn và p - * được tô mầu đen) - * - * (p) (cn) - * / \ / \ - * N cn --> P S - * \ / \ - * S N DN - * \ - * DN - */ \ - /* Trường hợp 1.4 - Xoay trái ở p + đảo mầu các nút, - * p và cn có thể có mầu bất kỳ trước khi xoay. Sau khi xoay - * mầu của cn không thay đổi, s có mầu cũ của p, p và dn được tô mầu đen. - * - * (p) (s) - * / \ / \ - * N S --> P Dn - * / \ / \ - * (cn) dn N (cn) - */ \ - /* - * Trường hợp 2.1 - Xoay phải ở p - * - * P S - * / \ / \ - * s N --> CN p - * / \ / \ - * CN DN s mới -> DN N - */ \ - /* - * Trường hợp 2.2 - Đảo mầu s, p có thể có mầu bất kỳ (mầu đỏ sau - * khi xử lý trường hợp 1) - * - * (p) (p) - * / \ / \ - * S N --> s N - * / \ / \ - * CN DN CN DN - * - * Vi phạm ràng buộc 5, có thể được khắc phục bằng cách đảo mầu p - * thành đen nếu nó là nút đỏ, hoặc đệ quy tại p nếu ngược lại. - */ \ - /* - * Trường hợp 2.3 - Xoay phải tại s (p có thể có mầu bất - * kỳ) - * - * (p) (p) - * / \ / \ - * S N --> cn N - * / \ \ - * cn DN S - * \ - * DN - * Nếu p là nút đỏ, thì cả p và CN đều là các nút đỏ sau khi xoay - * => Vi phạm ràng buộc 4. - * - * + Đường đi từ p qua cn sau đó rẽ về phía N bị giảm một - * nút đen (S, vi phạm tính chất 5). - * - * Các vấn đề này được xử lý trong trường hợp 4: Sau khi - * xoay trái tại top, cn được tô bằng mầu của p, dn và p - * được tô mầu đen) - * - * (p) (cn) - * / \ / \ - * N cn --> P S - * \ / \ - * S N DN - * \ - * DN - */ \ - /* Trường hợp 2.4 - Xoay phải ở p + đảo mầu các nút, - * p và cn có thể có mầu bất kỳ trước khi xoay. Sau khi xoay - * mầu của cn không thay đổi, s có mầu cũ của p, p và dn được tô mầu đen. - * - * (p) (s) - * / \ / \ - * S N --> DN P - * / \ / \ - * dn (cn) (cn) N - */ \ while (1) { \ s = p->right; \ if (n != s) { \ if (TIS_RED(s)) { \ - /* Trường hợp 1.1 */ \ + /* Trường hợp 1 - Xoay trái ở p + * + * P S + * / \ / \ + * N s --> p DN + * / \ / \ + * CN DN N CN <- s mới + */ \ prefix##rotate_## left(t, p); \ TPAINT_RED(p); \ TPAINT_BLACK(s); \ @@ -379,7 +266,19 @@ static inline void prefix##delete_fixup(struct tname *t, struct TNN(tname)* p) { if (TIS_BLACK(dn)) { \ cn = s->left; \ if (TIS_BLACK(cn)) { \ - /* Trường hợp 1.2 */ \ + /* + * Trường hợp 2 - Đảo mầu s, p có thể có mầu bất kỳ (có mầu đỏ + * sau khi xử lý trường hợp 1) + * + * (p) (p) + * / \ / \ + * N S --> N s + * / \ / \ + * CN DN CN DN + * + * Vi phạm ràng buộc 5 có thể được khắc phục bằng cách đảo mầu p + * thành đen nếu nó là nút đỏ, hoặc đệ quy tại p nếu ngược lại. + */ \ TPAINT_RED(s); \ if (TIS_RED(p)) { \ TPAINT_BLACK(p); \ @@ -392,11 +291,48 @@ static inline void prefix##delete_fixup(struct tname *t, struct TNN(tname)* p) { } \ break; \ } \ - /* Trường hợp 1.3 */ \ + /* + * Trường hợp 3 - Xoay phải tại s (p có thể có mầu bất kỳ) + * + * (p) (p) + * / \ / \ + * N S --> N cn + * / \ \ + * cn DN S + * \ + * DN + * Lưu ý: + p có thể là nút đỏ, và nếu như vậy thì cả p và + * cn đều là các nút đỏ sau khi xoay (vi phạm ràng buộc 4). + * + * + Đường đi từ p qua cn sau đó rẽ về phía N bị giảm 1 + * nút đen (S) => vi phạm tính chất 5. + * + * Các vấn đề này được xử lý trong trường hợp 4: Sau khi + * xoay trái tại p, cn được tô bằng mầu của p, dn và p + * được tô mầu đen) + * + * (p) (cn) + * / \ / \ + * N cn --> P S + * \ / \ + * S N DN + * \ + * DN + */ \ prefix##rotate_## right(t, s); \ s = p->right; \ } \ - /* Trường hợp 1.4 */ \ + /* Trường hợp 4 - Xoay trái ở p + đảo mầu các nút, + * p và cn có thể có mầu bất kỳ trước khi xoay. Sau khi xoay + * mầu của cn không thay đổi, s có mầu cũ của p, + * còn p và dn được tô mầu đen. + * + * (p) (s) + * / \ / \ + * N S --> P DN + * / \ / \ + * (cn) dn N (cn) + */ \ dn = s->right; \ prefix##rotate_ ##left(t, p); \ TPAINT(s, p->color); \ @@ -404,9 +340,9 @@ static inline void prefix##delete_fixup(struct tname *t, struct TNN(tname)* p) { TPAINT_BLACK(dn); \ break; \ } else { \ + /* Đối xứng với trường hợp n là con trái của p */ \ s = p->left; \ if (TIS_RED(s)) { \ - /* Trường hợp 2.1 */ \ prefix##rotate_## right(t, p); \ TPAINT_RED(p); \ TPAINT_BLACK(s); \ @@ -416,7 +352,6 @@ static inline void prefix##delete_fixup(struct tname *t, struct TNN(tname)* p) { if (TIS_BLACK(dn)) { \ cn = s->right; \ if (TIS_BLACK(cn)) { \ - /* Trường hợp 2.2 */ \ TPAINT_RED(s); \ if (TIS_RED(p)) { \ TPAINT_BLACK(p); \ @@ -429,11 +364,9 @@ static inline void prefix##delete_fixup(struct tname *t, struct TNN(tname)* p) { } \ break; \ } \ - /* Trường hợp 2.3 */ \ prefix##rotate_## left(t, s); \ s = p->left; \ } \ - /* Trường hợp 2.4 */ \ dn = s->left; \ prefix##rotate_ ##right(t, p); \ TPAINT(s, p->color); \