Hoe ze efficiënt vinden de laatste sleutel en waarde in GTree

stemmen
0

Ik moet een aantal functies uit te breiden ontwikkelen glib2 GTreemet:

  • vinden eerste element
  • Zoek last
  • vinden dichtstbijzijnde (vloer, ceil, grootst minder dan, althans groter dan)

Het vinden van de eerste is eenvoudig. U stopt gewoon de g_tree_foreach()Calback na de eerste. Maar hoe je het laatste element te vinden zonder het doorkruisen van de hele boom ?

Ik dacht dat ik zou kunnen gebruiken g_tree_search()met een callback dat houdt het retourneren van een positieve waarde totdat gevonden, maar hoe weet ik dat ik ben momenteel op de laatste element?

#include <stdio.h>
#include <sys/types.h>
#include <string.h>

#include <glib.h>

static
gint compare_int(gconstpointer p1, gconstpointer p2) {
    int i1 = GPOINTER_TO_INT(p1);
    int i2 = GPOINTER_TO_INT(p2);
    //printf(%d %d\n, i1, i2);
    return i1 == i2 ? 0 : i1 > i2 ? 1 : -1;
}


static
gboolean traverse(gpointer key, gpointer value, gpointer data) {
    //int ikey = GPOINTER_TO_INT(key);
    const char *sval = (const char *)value;
    printf(%s\n, sval);
    return FALSE;
}

static
gint find_last(gconstpointer p, gpointer user_data) {
    return 1;
}

static inline const char *NULS(const char *s) {
    return s ? s : NULL;
}

int main(int argc, char *argv[]) {
    GTree *tree = g_tree_new(compare_int);
    g_tree_insert(tree, GINT_TO_POINTER(10), ten);
    g_tree_insert(tree, GINT_TO_POINTER(-99), minus ninety-nine);
    g_tree_insert(tree, GINT_TO_POINTER(8), eight);
    g_tree_foreach(tree, traverse, NULL);
    printf(=======\n%s\n, NULS((const char*)g_tree_search(tree, (GCompareFunc)find_last, NULL)));
    return 0;
}
De vraag is gesteld op 03/06/2017 om 21:33
bron van user
In andere talen...                            


1 antwoorden

stemmen
0

Ik wilde niet dat mijn eigen boom volledig uit te voeren, want ik wilde geavanceerd zoeken op het uitvoeren van GTreeinstances ontvangen van 3rd-party code.

In plaats daarvan dacht ik dat Glib auteurs nauwelijks hun interne structuren zou veranderen deze dagen en dat ik kon hun akkers direct te gebruiken.

Het resultaat is de uitgebreide versie van de interne functie g_tree_find_node()uit gtree.c. Ik voegde twee parameters te controleren of wil eerst, of het dichtstbijzijnde knooppunt. Het algoritme voor het dichtstbijzijnde knooppunten verschilt van Java TreeMap, omdat onze knooppunt een pointer aan haar moedermaatschappij heeft. Volledige code met de unit test is hier: gtreeex.c.

typedef enum {
    FIND_EXACT = 0,
    FIND_FLOOR = 0x2,
    FIND_CEIL  = 0x20,
    FIND_LOWER = (FIND_FLOOR + 1),
    FIND_HIGHER = (FIND_CEIL + 1)
} find_mode;

static GTreeNode *
g_tree_find_node_ex (GTree        *tree,
                  gconstpointer key,
                  GCompareDataFunc key_compare,
                  find_mode mode
                  )
{
    GTreeNode *node;
    gint cmp;
    GTreeNode *last_lesser_node = NULL;
    GTreeNode *last_greater_node = NULL;

    node = tree->root;
    if (!node)
        return NULL;

    while (1)
        {
            cmp = key_compare (key, node->key, tree->key_compare_data);
            if (cmp == 0) {
                if (mode == FIND_LOWER) {
                    cmp = -1;
                } else if (mode == FIND_HIGHER) {
                    cmp = 1;
                } else {
                    return node;
                }
            }

            if (cmp < 0)
                {
                    if (!node->left_child) {
                        if ( (mode & FIND_FLOOR) ) {
                            return last_lesser_node; /* can be null */
                        }
                        if ( (mode & FIND_CEIL) ) {
                            return node;
                        }
                        return NULL;
                    }

                    last_greater_node = node;
                    node = node->left;
                }
            else
                {
                    if (!node->right_child) {
                        if ( (mode & FIND_CEIL) ) {
                            return last_greater_node; /* can be null */
                        }
                        if ( (mode & FIND_FLOOR) ) {
                            return node;
                        }
                        return NULL;
                    }

                    last_lesser_node = node;
                    node = node->right;
                }
        }
}

Voor betere prestaties is het mogelijk om preprocessor macro's te gebruiken in plaats van de twee nieuwe parameters, te vervangen ifmet #ifen omvatten de bits header meerdere keren.

antwoordde op 04/07/2017 om 17:47
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more