Как эффективно найти последний ключ и значение в GTree

голоса
0

Мне нужно разработать набор функций , чтобы расширить glib2 GTreeс:

  • найти первый элемент
  • найти последний
  • найти ближайший (пол, CEIL, наибольшее меньше, меньше, чем больше)

Обнаружение первого легко. Вы просто остановить g_tree_foreach()Колбек после первого. Но как найти последний элемент без обхода всего дерева ?

Я думал , что я мог бы использовать g_tree_search()с обратным вызовом , который постоянно возвращается положительное значение , пока не найдено, но , как я знаю , что я в данный момент на последнем элементе?

#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;
}
Задан 03/06/2017 в 21:33
источник пользователем
На других языках...                            


1 ответов

голоса
0

Я не хотел , чтобы в полной мере реализовать свое собственное дерево, потому что я хотел , чтобы выполнить расширенный поиск на GTreeэкземплярах , полученных от третьих сторон коды.

Вместо этого я думал, что GLIB авторы вряд ли изменят свои внутренние структуры, в эти дни, и что я мог бы использовать свои поля непосредственно.

Результатом является расширенной версией внутренней функции g_tree_find_node()от gtree.c. Я добавил два параметра для управления , хочу ли я первый, последний или ближайший узел. Алгоритм для ближайших узлов отличается от Явы TreeMap, потому что наш узел не имеет указателя на свой родитель. Полный код с модульным тестированием здесь: 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;
                }
        }
}

Для лучшей производительности , что можно использовать макросы препроцессора вместо двух новых параметров, заменить ifс #ifи включает в себя биты заголовок несколько раз.

Ответил 04/07/2017 в 17:47
источник пользователем

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