Jak skutecznie znaleźć ostatni klucz i wartość w GTree

głosy
0

Muszę opracować zestaw funkcji, które rozciągają się glib2 GTreez:

  • znaleźć pierwszy element
  • znaleźć ostatni
  • znaleźć najbliższy (podłoga, ceil, największy mniej niż co najmniej większy niż)

Znalezienie pierwszy jest łatwe. Wystarczy zatrzymać g_tree_foreach()Calback po raz pierwszy. Ale jak znaleźć ostatni element bez przechodzenia całego drzewa ?

Myślałem, że mogę skorzystać g_tree_search()z wywołania zwrotnego, który utrzymuje powrocie wartość dodatnią, aż znalazł, ale skąd mam wiedzieć, że jestem obecnie na ostatnim elemencie?

#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;
}
Utwórz 03/06/2017 o 21:33
źródło użytkownik
W innych językach...                            


1 odpowiedzi

głosy
0

Nie chciałem, aby w pełni realizować własne drzewo, bo chciałem, aby wykonać wyszukiwanie zaawansowane w GTreeprzypadkach otrzymanych z kodu 3rd partii.

Zamiast Myślałem, że autorzy GLib raczej nie zmieni ich struktur wewnętrznych w tych dniach i że mogę używać bezpośrednio swoich dziedzinach.

Rezultatem jest rozszerzoną wersją funkcji wewnętrznej g_tree_find_node()od gtree.c. Dodałem dwa parametry do kontrolowania, czy chcę pierwsza, ostatnia lub najbliższy węzeł. Algorytm do najbliższych węzłów różni się od Javy TreeMap, ponieważ nasz węzeł nie posiada wskaźnik do jego rodzica. Pełny kod z testów jednostkowych jest tutaj: 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;
                }
        }
}

Dla lepszej wydajności jest możliwe, aby korzystać z makr preprocesora zamiast dwóch nowych parametrów, wymienić ifz #ifobejmują bity nagłówka wielokrotnie.

Odpowiedział 04/07/2017 o 17:47
źródło użytkownik

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