From: Attractive Chaos Date: Thu, 19 Dec 2019 18:35:12 +0000 (-0500) Subject: RMQ apparently working on a small dataset X-Git-Url: http://www.kaiwu.me/postgresql/commit/static/gitweb.js?a=commitdiff_plain;h=edea354917220a037ec9e5ea9f9a4b5835cd0d25;p=klib.git RMQ apparently working on a small dataset --- diff --git a/krmq.h b/krmq.h index bbb2164..b2ba944 100644 --- a/krmq.h +++ b/krmq.h @@ -107,6 +107,48 @@ int main(void) { return (__type*)p; \ } +#define __KRMQ_RMQ(suf, __scope, __type, __head, __cmp, __lt2) \ + __scope __type *krmq_rmq_##suf(const __type *root, const __type *lo, const __type *up) { /* CLOSED interval */ \ + const __type *p = root, *path[2][KRMQ_MAX_DEPTH], *min; \ + int plen[2] = {0, 0}, pcmp[2][KRMQ_MAX_DEPTH], i, cmp, lca; \ + if (root == 0) return 0; \ + while (p) { \ + cmp = __cmp(lo, p); \ + path[0][plen[0]] = p, pcmp[0][plen[0]++] = cmp; \ + if (cmp < 0) p = p->__head.p[0]; \ + else if (cmp > 0) p = p->__head.p[1]; \ + else break; \ + } \ + p = root; \ + while (p) { \ + cmp = __cmp(up, p); \ + path[1][plen[1]] = p, pcmp[1][plen[1]++] = cmp; \ + if (cmp < 0) p = p->__head.p[0]; \ + else if (cmp > 0) p = p->__head.p[1]; \ + else break; \ + } \ + for (i = 0; i < plen[0] && i < plen[1]; ++i) \ + if (path[0][i] == path[1][i] && pcmp[0][i] <= 0 && pcmp[1][i] >= 0) \ + break; \ + if (i == plen[0] || i == plen[1]) return 0; /* no elements in the closed interval */ \ + lca = i, min = path[0][lca]; \ + for (i = lca + 1; i < plen[0]; ++i) { \ + if (pcmp[0][i] <= 0) { \ + if (__lt2(path[0][i], min)) min = path[0][i]; \ + if (path[0][i]->__head.p[1] && __lt2(path[0][i]->__head.p[1]->__head.s, min)) \ + min = path[0][i]->__head.p[1]->__head.s; \ + } \ + } \ + for (i = lca + 1; i < plen[1]; ++i) { \ + if (pcmp[1][i] >= 0) { \ + if (__lt2(path[1][i], min)) min = path[1][i]; \ + if (path[1][i]->__head.p[0] && __lt2(path[1][i]->__head.p[0]->__head.s, min)) \ + min = path[1][i]->__head.p[0]->__head.s; \ + } \ + } \ + return (__type*)min; \ + } + #define __KRMQ_ROTATE(suf, __type, __head, __lt2) \ /* */ \ static inline void krmq_update_min_##suf(__type *p, const __type *q, const __type *r) { \ @@ -257,7 +299,7 @@ int main(void) { r->__head.size = p->__head.size - 1; \ } \ } \ - for (i = d - 1; i >= 0; --i) /* not sure why adding condition "path[i]==p" doesn't work */ \ + for (i = d - 1; i >= 0; --i) /* not sure why adding condition "path[i]->__head.s==p" doesn't work */ \ krmq_update_min_##suf(path[i], path[i]->__head.p[0], path[i]->__head.p[1]); \ while (--d > 0) { \ __type *q = path[d]; \ @@ -361,6 +403,7 @@ int main(void) { */ #define krmq_find(suf, root, x, cnt) krmq_find_##suf(root, x, cnt) #define krmq_interval(suf, root, x, lower, upper) krmq_interval_##suf(root, x, lower, upper) +#define krmq_rmq(suf, root, lo, up) krmq_rmq_##suf(root, lo, up) /** * Delete a node from the tree @@ -419,6 +462,7 @@ int main(void) { #define KRMQ_INIT2(suf, __scope, __type, __head, __cmp, __lt2) \ __KRMQ_FIND(suf, __scope, __type, __head, __cmp) \ + __KRMQ_RMQ(suf, __scope, __type, __head, __cmp, __lt2) \ __KRMQ_ROTATE(suf, __type, __head, __lt2) \ __KRMQ_INSERT(suf, __scope, __type, __head, __cmp, __lt2) \ __KRMQ_ERASE(suf, __scope, __type, __head, __cmp, __lt2) \ diff --git a/test/krmq_test.c b/test/krmq_test.c index 32b48ba..8af20ca 100644 --- a/test/krmq_test.c +++ b/test/krmq_test.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -38,6 +39,27 @@ int check(struct my_node *p, int *hh, int *min) } else return 0; } +int check_rmq(const struct my_node *root, int lo, int hi) +{ + struct my_node s, t, *p, *q; + krmq_itr_t(my) itr; + int min = INT_MAX; + s.key = lo, t.key = hi; + p = krmq_rmq(my, root, &s, &t); + krmq_interval(my, root, &s, 0, &q); + if (p == 0) return -1; + krmq_itr_find(my, root, q, &itr); + do { + const struct my_node *r = krmq_at(&itr); + if (r->key > hi) break; + //fprintf(stderr, "%c\t%d\n", r->key, r->val); + if (r->val < min) min = r->val; + } while (krmq_itr_next(my, &itr)); + assert((min == INT_MAX && p == 0) || (min < INT_MAX && p)); + if (min != p->val) fprintf(stderr, "rmq_min %d != %d\n", p->val, min); + return min; +} + int print_tree(const struct my_node *p) { int c = 1; @@ -95,6 +117,7 @@ int main(void) if (p != q) free(p); check(root, &h, &min); } + shuffle(n, buf); for (i = 0; i < n/2; ++i) { t.key = buf[i]; @@ -105,6 +128,12 @@ int main(void) } check_and_print(root); + check_rmq(root, '0', '9'); + check_rmq(root, '!', '~'); + check_rmq(root, 'A', 'Z'); + check_rmq(root, 'F', 'G'); + check_rmq(root, 'a', 'z'); + krmq_itr_first(my, root, &itr); do { const struct my_node *r = krmq_at(&itr);