Рис. 14.2
. Вершины дерева и их указателиДля упрощения использования возвращенного указателя вы могли бы рассмотреть определение макроса:
#define tree_data(ptr, type)(*(type**)(ptr))
...
struct employee *e;
void *vp;
vp = tfind(&key, root, emp_name_id_compare);
if (vp != NULL) { /* it's there, use it */
e = tree_data(vp, struct employee);
/* использование сведений в *e ... */
}
14.4.5. Обход дерева: twalk()
Функция twalk()
следующим образом:typedef enum { preorder, postorder, endorder, leaf } VISIT;
void twalk(const void *root,
void (*action)(const void *nodep, const VISIT which,
const int depth));
Первый параметр является корнем дерева (не указателем на корень). Второй является указателем на функцию обратного вызова, которая вызывается с тремя аргументами, указателем на исследуемую вершину дерева; типом перечисления, указывающим, как осуществляется обход данной вершины; и целого, обозначающего глубину текущей вершины (корень находится на глубине 0, как объяснялось ранее).
Использование функции обратного вызова здесь такое же, как для nftw()
nftw()»). Там функция обратного вызова вызывается для каждого объекта в файловой системе. Здесь функция обратного вызова вызывается для каждого объекта, хранящегося в дереве.Есть несколько способов прохождения, или «обхода», двоичного дерева:
• Левая вершина, родительская вершина, правая вершина.
• Родительская вершина, левая вершина, правая вершина.
• Левая вершина, правая вершина, родительская вершина.
Функция GLIBC twalk()
VISIT указывают, на какой стадии произошла встреча с этой вершиной:preorder
postorder
endorder
leaf
ЗАМЕЧАНИЕ
. Использованная здесь терминология не соответствует точно той, которая используется в формальных руководствах по структурированию данных. Там используются термины inorder, preorder и postorder для обозначения соответствующих трех перечисленных ранее способов прохождения дерева. Таким образом,twalk() использует прохождение по типу preorder, но использует именованные константы preorder и т.д. для обозначения того, на какой стадии была посещена вершина. Это может сбивать с толку.Следующая программа, ch14-tsearch.c
struct employee и функцию emp_name_id_compare() из раздела 6.2 «Функции сортировки и поиска».1 /* ch14-tsearch.c --- демонстрация управления деревом */
2
3 #include
4 #include
5 #include
6
7 struct employee {
8 char lastname[30];
9 char firstname[30];
10 long emp_id;
11 time_t start_date;
12 };
13
14 /* emp_name_id_compare --- сравнение по имени, затем no ID */
15
16 int emp_name_id_compare(const void *e1p, const void *e2p)
17 {
18 const struct employee *e1, *e2;
19 int last, first;
20
21 e1 = (const struct employee*)e1p;
22 e2 = (const struct employee*)e2p;
23
24 if ((last = strcmp(e1->lastname, e2->lastname)) != 0)
25 return last;
26
27 /* фамилии совпадают, проверить имена */