Wie effizient letzte Schlüssel und Wert in GTree finden

stimmen
0

Ich brauche eine Reihe von Funktionen zu erweitern , um die Entwicklung glib2 GTreemit:

  • finden erstes Element
  • finden letzte
  • findet nächsten (Boden, ceil, am größten weniger als, dest größer als)

Ersten zu finden , ist einfach. Sie halten einfach den g_tree_foreach()Calback nach dem ersten. Aber wie das letzte Element zu finden , ohne den gesamten Baum durchquert ?

Ich dachte , ich könnte g_tree_search()mit einem Rückruf, bis gefunden Rückkehr einen positiven Wert hält, aber wie ich weiß , ich bin zur Zeit auf dem letzten 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;
}
Veröffentlicht am 03/06/2017 um 21:33
quelle vom benutzer
In anderen Sprachen...                            


1 antworten

stimmen
0

Ich wollte nicht in vollem Umfang zu meinem eigenen Baum implementieren, weil ich erweiterte Suche auf ausführen wollte GTreevon 3rd-Party - Code erhalten Instanzen.

Stattdessen dachte ich, dass Glib Autoren kaum ihre internen Strukturen in diesen Tagen ändern würde und dass ich ihre Felder direkt nutzen könnten.

Das Ergebnis ist die erweiterte Version der internen Funktion g_tree_find_node()aus gtree.c. Ich habe zwei Parameter zu steuern , ob ich will ersten, letzte oder nächsten Knoten. Der Algorithmus für die nächste Knoten unterscheidet sich von Java TreeMap, weil unser Knoten nicht einen Zeiger auf seine Eltern hat. Full - Code mit dem Unit - Test ist 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;
                }
        }
}

Für eine bessere Leistung ist es möglich , Präprozessormakros anstelle der beiden neuen Parameter, ersetzen die Verwendung ifmit #ifund umfassen die Bits Header mehrere Male.

Beantwortet am 04/07/2017 um 17:47
quelle vom benutzer

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