¿Cómo encontrar eficientemente última clave y valor en GTree

votos
0

Necesito desarrollar un conjunto de funciones para extender glib2 GTreecon:

  • encontrar primer elemento
  • encontrar la última
  • encontrar más cercano (piso, ceil, mayor menor que, por lo menos mayor que)

Encontrar primera es fácil. Sólo tiene que detener el g_tree_foreach()callback después de la primera. Pero, ¿cómo encontrar el último elemento sin recorrer todo el árbol ?

Pensé que podía usar g_tree_search()con una devolución de llamada que mantiene devolver un valor positivo hasta que se encuentran, pero ¿cómo sé que estoy actualmente en el último elemento?

#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;
}
Publicado el 03/06/2017 a las 18:33
fuente por usuario
En otros idiomas...                            


1 respuestas

votos
0

No quería aplicar plenamente mi propio árbol, porque quería realizar una búsqueda avanzada en GTreecasos recibidos del código de tercera parte.

En vez pensé que los autores Glib difícilmente cambiar sus estructuras internas en estos días y que podría utilizar sus campos directamente.

El resultado es la versión extendida de la función interna g_tree_find_node()de gtree.c. He añadido dos parámetros para controlar si quiero primero, último o nodo más cercano. El algoritmo para los nodos más cercanos se diferencia de Java TreeMap, porque nuestro nodo no tiene un puntero a su padre. Código completo con la prueba de unidad está aquí: 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;
                }
        }
}

Para un mejor rendimiento que es posible utilizar macros del preprocesador en lugar de los dos nuevos parámetros, reemplace ifcon #ife incluir los bits de cabecera varias veces.

Respondida el 04/07/2017 a las 14:47
fuente por usuario

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