- •О.Л. Викентьева, А.Н. Гусин, O.A. Полякова
- •ПРОЕКТИРОВАНИЕ ПРОГРАММ И ПРОГРАММИРОВАНИЕ НА C++
- •1. СТРУКТУРНОЕ ПРОГРАММИРОВАНИЕ
- •10.1. Базовые конструкции структурного программирования
- •10.3. Составные операторы
- •10.4. Операторы выбора
- •10.5. Операторы циклов
- •10.6. Операторы перехода
- •11. ПРИМЕРЫ РЕШЕНИЯ ЗАДАЧ С ИСПОЛЬЗОВАНИЕМ ОСНОВНЫХ ОПЕРАТОРОВ C++
- •11.2. Программирование арифметических циклов
- •11.3. Программирование итерационных циклов
- •11.4. Программирование вложенных циклов
- •12. МАССИВЫ
- •12.1. Определение массива в C/C++
- •12.2. Примеры решения задач с использованием массивов
- •13. УКАЗАТЕЛИ
- •13.1. Понятие указателя
- •13.2. Динамическая память
- •13.3. Операции с указателями
- •14. ССЫЛКИ
- •15.3. Динамические массивы
- •СИМВОЛЬНАЯ ИНФОРМАЦИЯ И СТРОКИ
- •16.1. Представление символьной информации
- •16.2. Библиотечные функции для работы со строками
- •16.3. Примеры решения задач с использованием строк
- •17. ФУНКЦИИ В C++
- •17.1. Объявление и определение функций
- •17.2. Прототип функции
- •17.3. Параметры функции
- •17.4. Локальные и глобальные переменные
- •17.5. Функции и массивы
- •17.5.1. Передача одномерных массивов как параметров функции
- •17.5.2. Передача строк в качестве параметров функций
- •17.5.3. Передача многомерных массивов в функцию
- •17.6. Функции с начальными значениями параметров (по умолчанию)
- •17.7. Подставляемые (inline) функции
- •17.8. Функции с переменным числом параметров
- •17.9. Рекурсия
- •17.11. Шаблоны функций
- •17.12. Указатель на функцию
- •17.13. Ссылки на функцию
- •18. ТИПЫ ДАННЫХ, ОПРЕДЕЛЯЕМЫЕ ПОЛЬЗОВАТЕЛЕМ
- •18.1. Переименование типов
- •18.2. Перечисления
- •18.3. Структуры
- •18.3.1. Работа со структурами
- •18.3.2. Битовые поля
- •18.3.3. Объединения
- •19. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ
- •19.1. Создание элемента списка
- •19.2. Создание списка из п элементов
- •19.3. Перебор элементов списка
- •19.4. Удаление элемента с заданным номером
- •19.5. Добавление элемента с заданным номером
- •19.6. Двунаправленные списки
- •19.7. Очереди и стеки
- •19.8. Бинарные деревья
- •19.9. Обход дерева
- •19.10. Формирование дерева
- •19.11. Удаление элемента из дерева
- •19.12. Обработка деревьев с помощью рекурсивного обхода
- •20. ПРЕПРОЦЕССОРНЫЕ СРЕДСТВА
- •20.1. Стадии и команды препроцессорной обработки
- •20.2. Директива #define
- •20.3. Включение текстов из файлов
- •20.4. Условная компиляция
- •20.5. Макроподстановки средствами препроцессора
- •21.1. Проектирование программы
- •21.2. Кодирование и документирование программы
- •СПИСОК ЛИТЕРАТУРЫ
- •ПРОЕКТИРОВАНИЕ ПРОГРАММ И ПРОГРАММИРОВАНИЕ НА C++
Run(p->left); //переход к левому п/д
Run(p->right);//переход к правому п/д
собработка p->data>
}
}
Результаты обхода сверху вниз для дерева поиска (см. рис. 20): 1 3 7 8 12 9 5.
19.10. Формирование дерева
Рассмотрим построение идеально сбалансированного дерева. При построении такого дерева надо распределять узлы таким обра зом, чтобы количество узлов в левом и правом поддеревьях отлича лось не более чем на единицу.
# include <iostream.h> struct point
{
int data; point*left,*right;
};
point* Tree(int n,point* p)
{
point*r; int nl,nr;
if(n==0){p=NULL;return p;}
nl=n/2;//считаем количество узлов в левом //поддереве
nr=n-nl-l;//считаем количество узлов
//в правом поддереве
r=new point;//создаем новый узел cout«" ?";
cin»r->data; //заполняем информационное
//поле
r->left=Tree(nl,r->left);//формируем //левое поддерево
r->right=Tree(nr,r->right);//формируем //правое поддерево
р=г;//связываем return р;
больше текущего осуществляется в правое поддерево, а меньше теку щего - в левое. Ключи не дублируется, поэтому необходимо прове рить, существует ли элемент с заданным ключом в дереве, и если су ществует, то завершить функцию добавления элемента.
p o i n t * |
f i r s t ( i n t d ) //ф о р м и р о в а н и е |
п ер в о го |
||||||
//э л е м е н т а |
д е р е в а |
|
|
|
|
|||
{ |
|
|
|
|
|
|
|
|
p o in t* |
p=new |
p o i n t ; |
|
|
|
|||
p -> k e y = d ; |
|
|
|
|
|
|||
p - > l e f t = 0 ; |
|
|
|
|
|
|||
p - > r ig h t= 0 ; |
|
|
|
|
||||
r e t u r n |
p ; |
|
|
|
|
|
||
} |
|
|
|
|
|
|
|
|
//д о б а в л е н и е |
эл ем ен та |
d в д ер ев о |
поиска |
|||||
P o in t* A d d ( p o in t* r o o t, i n t d) |
|
|
||||||
{ |
|
|
|
|
|
|
|
|
P o in t* p = r o o t, * r; |
|
|
|
|||||
//ф л а г |
для п роверки сущ ествован ия |
элем ен та d |
||||||
b o o l o k = f a ls e ; |
|
|
|
|||||
w h ile(p & & !ok) |
|
|
|
|
||||
{ |
|
r= p ; |
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
if(d = = p - > k e y ) o k = tru e ; |
|
|
||||
|
|
e l s e |
|
|
|
|
|
|
//п о д д е р е в о |
i f ( d < p - > k e y ) p = p - > l e f t ; //п о й т и в л ев о е |
|||||||
e l s e |
p = p - > r i g h t ; //п о й т и |
в |
п р аво е |
|||||
//п о д д е р е в о |
||||||||
|
|
|
|
|
|
|||
} |
|
|
|
|
|
|
|
|
i f ( o k ) |
r e t u r n |
р ;//н а й д е н о , не |
добавл яем |
|||||
//с о з д а е м |
у з е л |
|
|
|
||||
p o in t* |
q=new |
p o i n t ( ) ; //в ы д ел и л и |
пам ять |
|||||
q -> k ey = d ; |
|
|
|
|
|
|||
q - > l e f t = 0 ; |
|
|
|
|
|
|||
q - > r ig h t = 0 ; |
|
|
|
|
||||
//д о б а в л я е м |
в л ев о е |
п одд ер ево |
|
|
||||
i f ( d < r - > k e y ) r - > l e f t = q ; |
|
|
||||||
//д о б а в л я е м |
в п р аво е |
п одд ер ево |
|
|
||||
e l s e |
r - > r i g h t |
=q; |
|
|
|
|||
r e t u r n |
q; |
|
|
|
|
|
19.11. Удаление элемента из дерева
Рассмотрим удаление элемента из дерева поиска (см. рис. 21). Следует учитывать следующие случаи:
1.Узла с требуемым ключом в дереве нет.
2.Узел с требуемым ключом является листом, т.е. не имеет потомков.
3.Узел с требуемым ключом имеет одного потомка.
4.Узел с требуемым ключом имеет двух потомков.
Впервом случае необходимо выполнить обход дерева и срав нить ключи элементов с заданным значением.
Во втором случае нужно заменить адрес удаляемого элемента ну левым. Для этого нужно выполнить обход дерева и заменить адрес
удаляемого элемента нулевым. Например, при удалении элемента с ключом 7 мы меняем левое адресное поле элемента с ключом 8 на 0.
Третий случай похож на второй, так как мы должны заменить адресное поле удаляемого элемента адресом его потомка. Например, при удалении элемента с ключом 8 мы меняем левое адресное поле элемента с ключом 9 на адрес элемента с ключом 7.
Самым сложным является четвертый случай, так как возникает вопрос, каким элементом мы должны заменить удаляемый элемент. Этот элемент должен иметь два свойства. Во-первых, он должен иметь не более одного потомка, а во-вторых, мы должны сохранить упорядоченность ключей, т.е. он должен иметь ключ либо не мень ший, чем любой ключ левого поддерева удаляемого узла, либо не больший, чем любой ключ правого поддерева удаляемого узла. Та ким свойством обладают два узла: самый правый узел левого подде рева удаляемого узла и самый левый узел правого поддерева удаляе мого узла. Любым из них и можно заменить удаляемый элемент. Например, при удалении узла 9 его можно заменить узлом 12 (самый левый узел правого поддерева удаляемого узла).
Для удаления будем использовать рекурсивную функцию.
/^вспомогательная переменная для удаления уз ла, имеющего двух потомков*/
point *q;
Point* Del(Point* r)
{
/*удаляет узел, имеющий двух потомков, заменяя его правым узлом левого поддерева*/
i f ( r - > r i g h t 1=0) r = D e l ( r - > r i g h t ) ; / / и д е м
/ / в п равое п о д д е р е в о |
|
e l s e / /д ош ли д о |
с а м о г о п р а в о г о у з л а |
{
/ / з а м е н я е м э т и м у з л о м у д а л я е м ы й q - > k e y = r - > k e y ;
q = r ;
r = r - > l e f t ;
}
r e t u r n г;
P o i n t * D e l e t e ( P o i n t * p , i n t KEY)
{
/ / P o i n t * q ;
i f ( p ) / / и щ е м у з е л
i f ( K E Y < p - > k e y ) / / и с к а т ь в л е в о м п о д д е р е в е p - > l e f t = D e l e t e ( p - > l e f t , K E Y ) ;
e l s e i f ( K E Y > p - > k e y ) / / и с к а т ь в п р а в о м
//поддереве
p->right=Delete(p->right, KEY); else//y3en найден
{
/ / у д а л е н и е
q = p ; / / з а п о м н и л и а д р е с у д а л я е м о г о у з л а / / у з е л и м ее т н е б о л е е о д н о г о п о т о м к а с л е в а
i f ( q - > r i g h t = = 0 )
p = q - > l e f t ; / / м е н я е м на п о т о м к а e l s e
/ / у з е л и м е е т н е б о л е е о д н о г о п о т о м к а с п р а в а i f ( q - > l e f t = = 0 )
p = q - > r i g h t ; / / м е н я е м на п о т о м к а e l s e / / у з е л и м е е т д в у х п о т о м к о в
p - > l e f t = D e l ( q - > l e f t ) ; d e l e t e q;
}
r e t u r n p;