GLib 자료구조 GTree – 균형잡힌 이진 트리 #1

주의: [GLib 자료구조 GTree - 균형잡힌 이진 트리 #1]의 가장 최근 판은 이곳에서 확인할 수 있습니다.

시작하며

크로스플랫폼 C 라이브러리인 GLib은 다양한 자료구조를 제공합니다.
그 중에서 균형잡힌 이진 트리(balanced binary tree)
많은 자료를 검색해야 하는 경우 노드를 이용해서 트리의 깊이를 줄이기 때문에
배열이나 리스트와 비교해서 탐색 속도가 빠르다는 장점이 있습니다.
GLib은 제공하는 균형잡힌 이진 트리의 자료형은 GTree 입니다.
GTree를 이용해서 트리를 구성하고, 자료를 추가 및 삭제하는 방법과
탐색하는 방법을 3회에 걸쳐 살펴봅니다.

관련 연구

준비물

GLib은 교차 개발환경을 지원하기 때문에 윈도우즈나 맥OS, 리눅스 등
다양한 운영체제와 컴파일러를 사용해서 라이브러리를 이용 할 수 있지만,
pkg-config를 지원하는 리눅스에서 gcc 를 이용하는 경우로 한정합니다.
개발 환경 구성은 다음과 같습니다:

  • Linux 2.6.27-10-generic #1 SMP i686 GNU/Linux
  • gcc (Ubuntu 4.3.2-1ubuntu11) 4.3.2
  • GLib 2.19.5

현재 GLib 의 최신 안정버전은 2.18 입니다.
GLib 2.19.5는 프로젝트 저장소에서 제공하는 개발용 최신 버전입니다.

지원하는 API 목록

지원하는 API 목록 및 자세한 설명은 GTK 공식 홈페이지에서 제공하는
온라인 GLib API 문서에서 확인할 수 있습니다.
자주 사용하는 API를 간단한 설명과 함께 분류하면 크게 다음처럼 나눌 수 있습니다:

  • 트리 생성 및 소멸
  • 노드 추가 및 제거, 변경
  • 트리 정보
  • 트리 탐색

다음은 트리 생성 및 소멸과 관련한 API 입니다:

  GTree*   g_tree_new             (GCompareFunc key_compare_func);

  GTree*   g_tree_new_with_data   (GCompareDataFunc key_compare_func,
                                   gpointer key_compare_data);

  GTree*   g_tree_new_full        (GCompareDataFunc key_compare_func,
                                   gpointer key_compare_data,
                                   GDestroyNotify key_destroy_func,
                                   GDestroyNotify value_destroy_func);

  void     g_tree_destroy         (GTree *tree);

다음은 노드 추가 및 제거, 변경과 관련한 API 입니다:

  void     g_tree_insert          (GTree *tree,
                                   gpointer key,
                                   gpointer value);

  gboolean g_tree_remove          (GTree *tree,
                                   gconstpointer key);

  gboolean g_tree_steal           (GTree *tree,
                                   gconstpointer key);

  void     g_tree_replace         (GTree *tree,
                                   gpointer key,
                                   gpointer value);

다음은 트리의 정보를 획득하기 위한 API 입니다:

  gint     g_tree_nnodes          (GTree *tree);
  gint     g_tree_height          (GTree *tree);

다음은 트리 탐색과 관련한 API 입니다:

  gpointer g_tree_lookup          (GTree *tree,
                                   gconstpointer key);

  gboolean g_tree_lookup_extended (GTree *tree,
                                   gconstpointer lookup_key,
                                   gpointer *orig_key,
                                   gpointer *value);

  void     g_tree_foreach         (GTree *tree,
                                   GTraverseFunc func,
                                   gpointer user_data);

  void     g_tree_traverse        (GTree *tree,
                                   GTraverseFunc traverse_func,
                                   GTraverseType traverse_type,
                                   gpointer user_data);

  gboolean (\*GTraverseFunc)      (gpointer key,
                                   gpointer value,
                                   gpointer data);

  enum     GTraverseType;

  gpointer g_tree_search          (GTree *tree,
                                   GCompareFunc search_func,
                                   gconstpointer user_data);

구현

예제 소스

GLib 라이브러리의 GTree 자료구조 및 API를 사용하고 컴파일 및 실행하는데
문제가 없는지 확인하기 위해 다음의 간단한 예제로 개발 환경을 점검해봅니다:

  gtree.c:
  #include <stdio.h>
  #include <glib.h>

  static gint
  my_compare (gconstpointer a,
              gconstpointer b)
  {
    gint _a;
    gint _b;

    _a = GPOINTER_TO_INT (a);
    _b = GPOINTER_TO_INT (b);

    return _a - _b;
  }

  static gint
  my_traverse (gpointer key,
               gpointer value,
               gpointer data)
  {
    gint _key;
    gint _value;

    _key   = GPOINTER_TO_INT (key);
    _value = GPOINTER_TO_INT (value);

    printf("key(%d) - value(%d)\n", _key, _value);

    return FALSE;
  }

  int
  main (int   argc,
        char *argv[])
  {
    GTree *tree;
    gint i;

    tree = g_tree_new (my_compare);

    for (i = 0; i < 20; ++i)
      {
        gint key, value;

        key   = i;
        value = 10 * i;

        g_tree_insert (tree, GINT_TO_POINTER (key), GINT_TO_POINTER (value));
      }

    g_tree_foreach (tree, my_traverse, NULL);

    g_tree_destroy (tree);

    return 0;
  }

컴파일 및 실행

컴파일 및 실행은 다음처럼 수행합니다:

  $ gcc -Wall `pkg-config --cflags --libs glib-2.0` -g -o gtree gtree.c
  $ ./gtree

실행 결과

상기 예제의 실행 결과는 다음과 같습니다:

  key(0) - value(0)
  key(1) - value(10)
  key(2) - value(20)
  key(3) - value(30)
  key(4) - value(40)
  key(5) - value(50)
  key(6) - value(60)
  key(7) - value(70)
  key(8) - value(80)
  key(9) - value(90)
  key(10) - value(100)
  key(11) - value(110)
  key(12) - value(120)
  key(13) - value(130)
  key(14) - value(140)
  key(15) - value(150)
  key(16) - value(160)
  key(17) - value(170)
  key(18) - value(180)
  key(19) - value(190)

정리하며

지금까지 트리 API와 노드 API로 나눌 수 있는 GTree의 API와
GTree를 이용하는 간단한 예제 및 컴파일 및 실행 과정을 통해
GLib이 제공하는 GTree에 대해서 개략적으로 살펴보았습니다.
다음 글에서는 GTree의 API가 제공하는 기본적인 트리 연산을 이용해서
실용적인 예제를 구현하고 GTree가 배열이나 리스트 자료구조에 비해
탐색 시 어느 정도의 속도향상을 기대할 수 있는지 알아봅니다.

Creative Commons License
This work, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 2.0 Korea License.
This entry was posted in Development and tagged , , , , . Bookmark the permalink.

Comments are closed.