Cum de a găsi în mod eficient cheie și ultima valoare în GTree

voturi
0

Am nevoie pentru a dezvolta un set de funcții de extindere glib2 GTreecu:

  • găsi prim element
  • găsi ultima
  • găsi cel mai apropiat (etaj, ceil, cel mai mare mai mică, cel mai mare)

Găsirea mai întâi este ușor. Pur și simplu opriți g_tree_foreach()calback după prima. Dar cum să găsiți ultimul element fără traversează întregul copac ?

Am crezut că pot folosi g_tree_search()cu un apel invers , care păstrează o valoare pozitivă revenind , până când a găsit, dar cum știu că sunt în prezent pe ultimul 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;
}
Întrebat 03/06/2017 la 21:33
sursa de către utilizator
În alte limbi...                            


1 răspunsuri

voturi
0

Nu am vrut să pună în aplicare pe deplin propriul meu copac, pentru că am vrut să efectueze căutare avansată în GTreecazurile primite de la codul 3rd-party.

În schimb, am crezut că autorii Glib ar schimba cu greu structurile lor interne în aceste zile și că am putea folosi domeniile lor direct.

Rezultatul este versiunea extinsă a funcției interne de g_tree_find_node()la gtree.c. Am adăugat doi parametri pentru a controla dacă vreau în primul rând, ultimul sau cel mai apropiat nod. Algoritmul pentru cele mai apropiate noduri difera de Java lui TreeMap, deoarece nodul nostru nu are un pointer la părintele său. Codul complet cu testul de unitate este aici: 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;
                }
        }
}

Pentru o performanță mai bună este posibil să se utilizeze macro - uri preprocesorul în loc de două noi parametri, înlocuiți ifcu #ifși includ biții de antet de mai multe ori.

Publicat 04/07/2017 la 17:47
sursa de către utilizator

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