Comment trouver efficacement la dernière touche et valeur GTree

voix
0

Je dois développer un ensemble de fonctions pour étendre glib2 GTreeavec:

  • trouver premier élément
  • trouver la dernière
  • le plus proche trouver (sol, Ceil, plus moins, moins supérieur)

Trouver première est facile. Vous arrêtez simplement le g_tree_foreach()Calback après la première. Mais comment trouver le dernier élément sans traverser l'arbre entier ?

Je pensais que je pouvais utiliser g_tree_search()avec un rappel qui revient sans cesse une valeur positive jusqu'à trouvée, mais comment puis-je sais que je suis actuellement sur le dernier élément?

#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;
}
Créé 03/06/2017 à 21:33
source utilisateur
Dans d'autres langues...                            


1 réponses

voix
0

Je ne voulais pas mettre pleinement en œuvre mon propre arbre, parce que je voulais effectuer une recherche avancée sur les GTreeinstances reçues à partir du code 3ème partie.

Au lieu de cela, je pensais que les auteurs Glib ne serait guère modifier leurs structures internes ces jours-ci et que je pouvais utiliser leurs champs directement.

Le résultat est la version étendue de la fonction interne g_tree_find_node()de gtree.c. J'ai ajouté deux paramètres pour contrôler si je veux d' abord, le dernier ou le noeud le plus proche. L'algorithme pour les noeuds les plus proches diffère de celle des java TreeMap, parce que notre nœud ne dispose pas d' un pointeur vers son parent. Code complet avec le test unitaire est ici: 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;
                }
        }
}

Pour de meilleures performances , il est possible d'utiliser des macros préprocesseur au lieu des deux nouveaux paramètres, remplacer ifavec #ifet inclure les bits d'en- tête plusieurs fois.

Créé 04/07/2017 à 17:47
source utilisateur

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