Hvordan du effektivt finne siste nøkkelen og verdien i GTree

stemmer
0

Jeg trenger å utvikle et sett med funksjoner for å utvide glib2 GTreemed:

  • finne første elementet
  • finne siste
  • finne nærmeste (gulv, himling, største mindre enn det minste større enn)

Finne første er enkelt. Du bare stoppe g_tree_foreach()calback etter først. Men hvordan finne den siste elementet uten traversering hele treet ?

Jeg trodde jeg kunne bruke g_tree_search()med en tilbakeringing som holder tilbake en positiv verdi til funnet, men hvordan vet jeg at jeg er for tiden på det siste elementet?

#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;
}
Publisert på 03/06/2017 klokken 21:33
kilden bruker
På andre språk...                            


1 svar

stemmer
0

Jeg ønsket ikke å fullt ut gjennomføre mitt eget tre, fordi jeg ønsket å utføre et avansert søk på GTreetilfeller mottatt fra tredje-parts kode.

I stedet tenkte jeg at Glib forfattere ville neppe endre sine interne strukturer i disse dager, og at jeg kunne bruke sine felt direkte.

Resultatet er en utvidet versjon av den interne funksjon g_tree_find_node()fra gtree.c. Jeg har lagt to parametere for å kontrollere om jeg vil først, sist eller nærmeste node. Algoritmen for nærmeste noder skiller seg fra Javas TreeMap, fordi vår node ikke har en peker til sin overordnede. Full kode med enheten testen er her: 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;
                }
        }
}

For bedre ytelse er det mulig å bruke preprosessor makroer i stedet for de to nye parametere, erstatte ifmed #ifog inkludere biter header flere ganger.

Svarte 04/07/2017 kl. 17:47
kilden bruker

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