Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Часть 2: бинарные деревья.

Лекция 1: введение в программирование. | Лекция 2: представление данных в компьютере. | Часть 1: хранение данных в компьютере. | Часть 2: типы данных языка Си. | Часть 1: основные операторы и их приоритеты. | Часть 2: функции. | Лекция 5: Функция main, функции ввода-вывода, препроцессор. | Лекция 6: массивы и строки, библиотечные функции ввода-вывода. | Лекция 7: операторы выбора, безусловный переход, циклы. | Лекция 8: структуры и объединения. |


Читайте также:
  1. A) именная часть составного сказуемого
  2. Cities-65: Радомышль. Часть 1. Вокзал и задворки центра
  3. Hearthlab часть 5: Исступление
  4. I ЧАСТЬ ВТОРАЯ
  5. III. Восполните пропущенную часть предложения.
  6. III. Восполните пропущенную часть предложения.
  7. III. Восполните пропущенную часть предложения.

Примером структуры данных, обработка которой практически невозможна без использования рекурсии, является бинарное дерево. Бинарное дерево – это структура, состоящая из одного элемента, называемого корнем, который ссылается либо на два других непересекающихся бинарных дерева, корни которых называются потомкам и данного элемента, либо не ссылается никуда. Под непересекающимися деревьями понимаются деревья, не имеющие общих элементов и связей между собой. В общем случае элемент имеет произвольное число потомков, а такая структура называется деревом [36].

Деревом, например, является организация любой файловой системы, поддерживающей каталоги. А треугольник Паскаля деревом не является, поскольку в нём два элемента могут ссылаться на один.

Для краткости рассмотрим только бинарные деревья. Из определения следует, какую структуру имеет элемент:

typedef struct BINTREE

{

void* data;

struct BINTREE* left;

struct BINTREE* right;

} bintree;

Поле data отвечает за данные, хранящиеся в элементе, а left и right – за его потомков. В них могут быть либо собственно указатели на потомков, либо NULL.

Как же пройти такую сложную структуру, с учётом того, что элемент не имеет указателя на предыдущий? С помощью рекурсии это делается элементарно:

void traversal(bintree* root)

{

/*some actions*/

if(root->left) traversal(root->left);

if(root->right) traversal(root->right);

return;

}

Этот алгоритм создан непосредственно по определению дерева: если элемент не имеет потомков, то обход текущего дерева закончен, а если имеет – обойти потомков. Например, такая функция выводит дерево на экран:

void print(bintree* root)

{

printf("%d\n", *((int*)root->data));

if(root->left) print(root->left);

if(root->right) print(root->right);

return;

}

Если её вызвать для дерева, изображённого на рисунке, то программа выведет

Эту функцию можно «украсить» следующим образом:

void print(bintree* root, int deep)

{

printf("%*d\n", deep, *((int*)root->data));

if(root->left) print((root->left), ++deep);

--deep;

if(root->right) print((root->right), ++deep);

--deep;

return;

}

При рекурсивном вызове этой функции для потомка значение переменной deep увеличивается, а при возврате – уменьшается. Таким образом, с точностью до переданного при первом вызове значения, deep равно расстоянию от текущего элемента до корня. Поэтому вывод этой функции будет выглядеть так:

Это нагляднее отражает структуру дерева.

Поскольку между корнем дерева и любым его элементом должен существовать путь, удаление элемента ведёт к удалению всех его потомков. А значит, удаление также должно быть реализовано рекурсивно. Однако непосредственно удаление элемента является невозможным из-за отсутствия связи между элементом и его предком[37]. Так что функция удаления потомков элемента будет выглядеть следующим образом:

void rmrf(bintree* root)

{

if(root->left) rmrf(root->left); else return;

if(root->right) rmrf(root->right); else return;

if(!((root->left->left)||(root->left->right)))

{

free(root->left->data);

free(root->left);

root->left=NULL;

}

if(!((root->right->left)||(root->right->right)))

{

free(root->right->data);

free(root->right);

root->right=NULL;

}

}

Логика этой функции такова: если текущий элемент потомков не имеет, то сделать с ним ничего невозможно, текущий вызов функции завершается. Если он имеет потомков, но те потомков не имеют, то их можно удалять. Если же и у потомков есть потомки, то нужно к ним переходить.

Вызов этой функции для элемента root->left рассмотренного дерева превратит его в такое:


Дата добавления: 2015-11-13; просмотров: 92 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
Лекция 9: связные списки.| Часть 3: динамическое программирование.

mybiblioteka.su - 2015-2024 год. (0.006 сек.)