]> git.kaiwu.me - klib.git/commitdiff
RMQ apparently working on a small dataset
authorAttractive Chaos <attractor@live.co.uk>
Thu, 19 Dec 2019 18:35:12 +0000 (13:35 -0500)
committerAttractive Chaos <attractor@live.co.uk>
Thu, 19 Dec 2019 18:35:12 +0000 (13:35 -0500)
krmq.h
test/krmq_test.c

diff --git a/krmq.h b/krmq.h
index bbb21648509309d080b8e70bde990b2530f465f9..b2ba94455dbb1e883ac9826192f345b833f1d351 100644 (file)
--- 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) \
index 32b48bad4334a75a553604d6cb39bee9224d187b..8af20ca720394db0be2ccd26ac92235846516e44 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <assert.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
@@ -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);