Файл: Подпись студента Проверил Трубаков А. О. 20 г.doc

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 09.11.2023

Просмотров: 98

Скачиваний: 4

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

СОДЕРЖАНИЕ

СОДЕРЖАНИЕ

1. ЛАБОРАТОРНАЯ РАБОТА №1

1.1. Задание

1.2. Решение

1.3. Демонстрация программы

2. ЛАБОРАТОРНАЯ РАБОТА №2

2.1. Задание

2.2. Решение

2.3. Демонстрация программы Добавим несколько факультетов и кафедр в изначально пустую очередь: Выполним извлечение из очереди (т.е. имитируем поступление нового компьютера): Заметим, что кафедра ИиПО исключилась из очереди факультета ФИТ, а сам факультет ушел в конец очереди факультетов.Выполним еще одно извлечение: Теперь ГиСД исключена из очереди ФОЦЭ, а сам ФОЦЭ помещен в хвост очереди факультетов.Добавим кафедру ВМ в очередь факультета ФИТ. Как и предполагалось: кафедра заняла место в хвосте очереди ФИТ; позиция факультета в очереди факультетов осталась той же. 3. ЛАБОРАТОРНАЯ РАБОТА №3 3.1. Задание Ввести произвольное сильно ветвящееся дерево. Выдать списки вершин:1) являющихся листьями;2) не являющихся листьями;3) родителей листьев;4) заданного уровня считая от вершины.3.2. Решение Следующая программа не только выполняет заданные операции для сильно ветвящихся деревьев, но и выполняет визуализацию дерева с изображением «веток». Чтение дерева осуществляется из файла. Это сделано, чтобы просто можно было загрузить дерево, не вводя его данные каждый раз заново с клавиатуры.#include #include #include #include // спец. значение, которым не может быть индекс в массиве#define SPECIAL_VALUE -1using namespace std;struct Node // структура УЗЕЛ ДЕРЕВА{int id; // идентификатор узлаint nKeys; // число ключей узлаint * keys; // ключи Node ** children; // потомки Node(int id, int MaxAllowedPower) // конструктор узла{ this->nKeys = 0; this->id = id; // ! если узел не листовой потомков на 1 больше, нежели ключейthis->keys = new int[MaxAllowedPower - 1]; this->children = new Node * [MaxAllowedPower]; for (int i = 0; i < MaxAllowedPower; i++) this->children[i] = NULL;} // является ли листом? bool IsLeaf() { return (this->children[0] == NULL); } // операция вывода в поток friend ostream & operator << (ostream & os, Node & v); int FindLastChild() // поиск самого правого сына {// если узел листовой, детей нетif (IsLeaf()) return SPECIAL_VALUE;// если не листовой, используем то, что у нас// ровно nKeys + 1 детей return nKeys; }// вывод поддерева с корнем this на экранvoid PrintTree(int level, // уровень узла int num_of_child, // каким по счёту сыном своего родителя является узелbool Vis[] // информация для вывода вертикальных частей веток);};// различные функции условий поиска узловbool IsLeaf(Node * v) { return v->IsLeaf(); }bool IsInternal(Node * v) { return !(v->IsLeaf()); }bool IsParentOfLeaf(Node * v){if (IsLeaf(v)) // если узел - лист, он точно не родитель листаreturn false;// все листья на одном уровне, потому достаточно// проверить, является ли 1-ый ребенок листомreturn IsLeaf(v->children[0]);}ostream & operator << (ostream & os, Node & v){ os << "id = " << v.id << ", ключи: "; for (int i = 0; i < v.nKeys; i++) {os << v.keys[i]; // если ключ не последнийif (i < v.nKeys - 1) os << ", ";} return os;}void Node::PrintTree(int level, int num_of_child, bool Vis[]){ for (int j = 0; j < 2; j++){ for (int i = 0; i < level - 1; i++){ if (Vis[i] == true) cout << "| "; else cout << " ";} if (level > 0){ if (j == 1) cout << "|_______"; else cout << "| ";} if (j < 1) cout << "\n"; }// выводим содержимое узлаcout << (*this) << "\n";if (this->IsLeaf() == true){ for (int i = 0; i < level; i++){ if (Vis[i] == true) cout << "| "; else cout << " ";} cout << "\n"; return;} int lchild = this->FindLastChild(); // рекурсивно вызываем функцию для потомков for (int i = 0; i <= nKeys; i++){ bool Temp[100]; if (level > 0) copy(Vis, Vis + level, Temp); Temp[level] = (i != lchild) ? true : false; if (this->children[i] != NULL) this->children[i]->PrintTree(level + 1, i, Temp); }}class SVD // класс СИЛЬНОВЕТВЯЩЕЕСЯ ДЕРЕВО{int MaxPower; // макс. степеньNode * root; // кореньint count; // счетчик для поиска// для загрузки одного узла из файлаvoid LoadNodeFromFile(ifstream * file, Node ** all, int index); // для загрузки узлов из файла void LoadNodesFromFile(ifstream * file); // удаление поддереваvoid DelSubtree(Node * rt);// поиск узлов с заданным условием с сохранением// их id в массив чисел void Finder(Node *rt, bool(*Filter)(Node *), int ids[]); // поиск узлов на заданном уровне void FindAtLevel(Node * rt, int level, int requiredLevel, int ids[]);public:// конструктор с загрузкой из файлаSVD(int MaxPower, char FileName[]); // вывод дерева friend ostream & operator << (ostream & os, SVD & derevo); // поиск по заданному условию int Finder(bool(*Filter)(Node *), int ids[]) {count = 0; // пока что ничего не найденоFinder(root, Filter, ids); return count; // вернуть число найденных узлов} // поиск узлов на заданном уровне int FindAtLevel(int requiredLevel, int ids[]) {count = 0; // пока что ничего не найденоFindAtLevel(root, 0, requiredLevel, ids); return count; // вернуть число найденных узлов }// деструктор

3.3. Демонстрация программы Тестовая коллекция деревьев (напротив каждой вершины поставлен ее идентификатор): Тест №1: Тест №2: Тест №3: Тест №4: 4. ЛАБОРАТОРНАЯ РАБОТА №4 4.1. Задание Имеется множество слов, т.е. строк, состоящих из букв а-я. Суммарная длина слов равна N. Алгоритмы сортировки с какой минимальной сложностью можно применить здесь? Написать программы, реализующие этот алгоритм, сравнить эффективность на примере другого метода.4.2. Решение Поскольку в общем случае все символы в каждой строке могут участвовать в сравнении с символами других строк, с которыми она сравнивается, и нельзя полагать, что значительная часть символов строк окажется незадействованной при сравнениях, то слова с суммарной длиной N в худшем случае нельзя отсортировать быстрее, чем за время O(N).Пример алгоритма минимального порядка сложности (далее реализуется именно он). При сортировке числовых данных используется такой алгоритм, как сортировка вставками в дерево. Нечто аналогичное реализуем для строк, но нам нужно подходящее именно для строк (т.е. не бинарное дерево поиска и не АВЛ-дерево). Это Trie-дерево. Все сортируемые строки добавляем в Trie-дерево, и дальше обходим Trie-дерево. Чтобы можно было хранить пары строк вида (W, W+Z), расширяем алфавит символом конца ввода, и тогда одно слово может быть началом другого. Время добавления строки длиной L составляет O(L), то есть дерево строится за время O(N). Обход дерева также выполняется за время O(N), поскольку оценка количества узлов составляет O(N).Преимущество над «быстрой сортировкой». Интерес представляет сравнение предложенной сортировки с сортировками, выполняемыми на основе массивов. Пусть n – количество слов. С ростом n отношение N/n становится стабильным (на основе аксиом теории вероятностей: средняя длина большого числа слов – показатель стабильный). Соответственно, попытки применить универсальные сортировки вроде «быстрой» сортировки при больших N и n характеризуются сложностью O(N log N), то есть при больших N «быстрая сортировка» уступит сортировке вставками в Trie-дерево. При небольших N и n сортировка вставками в Trie-дерево невыгодна, потому что хотя операций немного, они довольно сложны. Например, довольно дорогостоящей является операция выделения памяти под узел с последующей инициализацией указателей в узле. Обход дерева также намного дороже, чем простой вывод на экран содержимого строкового массива.#include #include #include #include #include #include #define ALPH_CARD 32 /* количество символов в алфавите */#define MAXWORDSZ 21 /* максимальный размер слова минус 1 */using namespace std;struct Node /* структура УЗЕЛ ДЕРЕВА */{Node * next[ALPH_CARD + 1]; /* указатели на потомков */Node(); /* конструктор */bool IsLeaf(); /* является ли узел листом? */int FindLastChild(); /* находим номер самого правого сына */};Node::Node(){ for (int i = 0; i < ALPH_CARD + 1; i++) {this->next[i] = NULL; /* потомков пока что нет */}}bool Node::IsLeaf(){ for (int i = 0; i < ALPH_CARD + 1; i++) if (this->next[i] != NULL) return false; return true;}int Node::FindLastChild(){ for (int i = ALPH_CARD; i >= 0; i--) if (this->next[i] != NULL) return i; return -1;}class TrieDerevo /* класс trie-дерево */{private:int pos; /* вспомогательное поле для подсчёта при поиске */Node *root; /* указатель на корень */char AlphStart; /* первый символ алфавита */int NumInAlph(char c) { return c - AlphStart; } /* определение, каким по счёту в алфавите заданный символ */void Print(Node *rt, int level, int num_of_child, bool Vis[]); /* вывод поддерева на экран */ void Add(char *word); /* добавление слова */ void DelTree(Node *rt); /* удаление поддерева */ // вывод строк в порядке их возрастания - вспомогательная функцияvoid PrintContent(Node * rt, char prefix[], int level);public: TrieDerevo(char c) { root = new Node; AlphStart = c; } /* конструктор */ bool AddFromFile(char *FileName); /* добавление коллекции из файла */void Print() { bool Vis[1]; Print(root, 0, -1, Vis); } /* вывод всего дерева на экран */ // вывод строк в порядке их возрастания - основная функцияvoid PrintContent() { this->PrintContent(this->root, "", 0); }

4.3. Демонстрация программы Самый сложный из тестов, с высокой вероятностью проявляющий «баги», если есть цепочка ситуаций, когда одно слово – начало другого. Далее «кон» – начало «конь» и «конюх», а «конь» – начало «коньяк» и «коньки» (имеем цепочку отношений «одно слово – начало другого»). Программа успешно прошла и такой запутанный тест. 5. ЛАБОРАТОРНАЯ РАБОТА №5 5.1. Задание Составить программу поиска записи с включением в сбалансированном бинарном дереве поиска (АВЛ-дереве).5.2. Решение Поиск с включением в АВЛ-дерево осуществляется следующим образом. 1. Сначала ведем спуск по дереву, как для обычного бинарного дерева поиска. Выбираем правое или левое направление движения в зависимости от результата сравнения ключа в текущем узле и вставляемого ключа. 2. При вставке ключа требуется проверить, не нарушены ли требования к показателю сбалансированности. В случае необходимости выполняется балансировка.Также дадим краткое пояснение визуализации дерева «с веточками» в консольном приложении (PrintTree ниже). Требуется использовать для каждого узла уровень и булев массив, который задает, где нужно выводить вертикальные полосы (символ «|») на текущей строке консольного окна (true – выводить полосу по соответствующей позиции, false – нет). 1. Выводим содержимое, предшествующее в строке содержимому корня поддерева (включая полосы). 2. Выводим корень. 3. Рекурсия для поддеревьев.#include #include #include #include #include #include using namespace std;// белый цвет текстаint white_color = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;// голубой цвет текстаint cyan_color = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;// получаем дескриптор для устройства выводаHANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);void SetColor(int color){// установка цвета текстаSetConsoleTextAttribute(handle, color);}struct node // структура для представления узлов АВЛ-дерева{int item; // элементunsigned char height; // высота поддерева с корнем в данном узлеnode * left, *right; // указатели на левое и правое поддеревьяnode(int item) // конструктор{ this->item = item;left = right = 0;height = 1;}};class Avlka{private:node *Root; // корень дерева// для запоминания, найден ли такой ключ,// при попытке добавить ключbool HasFound;/* Вспомогательные функции, связанные с высотойheight она может работать с нулевыми указателями(с пустыми деревьями);bfactor вычисляет показатель сбалансированности для узла(и работает только с ненулевыми указателями);fixheight восстанавливает корректное значение поля height заданного узла(при условии, что значения этого поля в правом и левом дочерних узлах являются корректными) * /*/ unsigned char height(node* p){ return p ? p->height : 0;} int bfactor(node* p) {// показатель сбалансированности поддерева с корнем preturn height(p->right) - height(p->left);} void fixheight(node* p){ unsigned char hl = height(p->left); unsigned char hr = height(p->right); p->height = (hl>hr ? hl : hr) + 1;} node* rotateright(node* p); // правый поворот вокруг p node* rotateleft(node* q); // левый поворот вокруг qnode* balance(node* p); // балансировка узла p node* Vstavka(node* p, int item); // вставка в дерево с корнем p // вывод поддерева на экран void PrintTree(node * rt, int level, int num_of_child, bool Vis[]); void DelTree(node * root); // удаление дереваpublic: // конструктор с построением по заданной// последовательностиAvlka(int A[], int n){ Root = NULL; for (int i = 0; i < n; i++) Vstavka(A[i]);} void PrintTree() // вывод дерева{ bool Vis[1];PrintTree(Root, 0, -1, Vis); }bool Vstavka(int item) // добавление отдельного элемента{ HasFound = false; Root = Vstavka(Root, item); // вставка считается неуспешной, если item// уже был в деревеreturn !HasFound;}

5.3. Демонстрация программы Сформируем дерево по случайным ключам. Обозначения: L - левое поддерево, R - правое поддерево, bfactor - разность высоты правого и левого поддерева (у АВЛ-дерева может быть только -1, 0 или 1).Пример вставки, когда балансировка не нужна: Заметим, что выполнена корректировка показателей сбалансированности. Продемонстрируем вставку для случая, когда баланс нарушится. Если вставить ключ 222 без балансировки, у поддерева с корнем 459 высота левого поддерева станет 2, а правого останется 0, т.е. показатель = -2. При вставке 222 программа осуществила балансировку: Еще несколько примеров вставки: Примеры попыток добавить существующий ключ: Тестирование показывает, что программа корректно работает, даже когда при вставке нарушается допустимый баланс поддеревьев корня. 6. ЛАБОРАТОРНАЯ РАБОТА №6 6.1. Задание Написать процедуру обхода графа G (выдачи на печать всех его вершин).6.2. Решение Существуют два базовых варианта – обход в глубину (DFS) и в ширину (BFS). Идея DFS заключается в том, что мы двигаемся от начальной вершины в определенном направлении (по определенному пути) до тех пор, пока можем. Если далее двигаться некуда («тупик» или все доступные вершины уже посещены), то мы возвращаемся назад (к точке разветвления или расхождения путей) и идем по другому маршруту. BFS подразумевает посещение соседей стартовой вершины, затем посещение соседей этих соседей и т.д.Для реализации DFS/BFS мы поддерживаем список открытых вершин – которые предстоит проверить, и массив флагов, указывающих, является ли каждая вершина посещенной. Изначально список открытых вершин содержит только начальную. Далее, для каждой вершины из списка открытых вершин выполняется раскрытие – сама вершина считается посещенной и извлекается из списка, а еще не посещенные смежные с ней вершины заносятся в список открытых. Если извлечение из списка открытых и добавление в список – с одного конца, имеем поиск в глубину (в данном случае его нерекурсивный способ), если с разных концов – в ширину. При наличии нескольких компонент связности такой обход нужно выполнить отдельно для каждой.#include #include #include #include #define MAXN 20#define FAIL -1using namespace std;// чтение матрицы смежности из файлаint ReadMatrix(char FileName[], bool A[MAXN][MAXN]){ ifstream file(FileName, ios::in); int n, cur;file >> n; // читаем число вершин// читаем матрицу for (int i = 0; i < n; i++) for (int j = 0; j < n; j++){ file >> cur; if (cur == 0) A[i][j] = false; else A[i][j] = true; }file.close();return n;}// поиск первой непосещённой вершины, начиная со start-ойint IndexOfNotVisit(bool Visited[], int start, int n){ for (int i = 0; i < n; i++) if (Visited[i] == false) return i; return FAIL;}void InitBoolArr(bool Arr[], int n){ for (int i = 0; i < n; i++) Arr[i] = false;}struct Node // узел списка вершин{int item; // номер вершиныNode * next; // указатель на следующий элементNode(int item){ this->item = item; this->next = NULL;}};class List // список{ Node * head, *tail;public: List() { head = NULL; } // ToHead = true - вставка в голову,// ToHead = false - вставка в хвост void Add(int item, bool ToHead) {if (head == NULL) // если список пустой{head = new Node(item);// единственный узел одновременно и голова, и хвост спискаtail = head; return;} if (ToHead == true){ Node * p = new Node(item);p->next = head;head = p;} else{ tail->next = new Node(item); tail = tail->next;}}// извлечение содержимого головы (с удалением головы)int ExtractHead(){ if (head == NULL) return FAIL; Node * q = head->next; int extracted = head->item; // запомнить, что было в голове delete head; // удалить головуhead = q; // кто был следующим за головой теперь головаreturn extracted;} bool Contains(int item) // поиск элемента item{ Node * cur = head; while (cur){ if (cur->item == item) return true;cur = cur->next;} return false;}

6.3. Демонстрация программы



for (int i = 0; i < n; i++)

{

// рандомное число от 1 до 1000

A[i] = rand() % 1001 + 1;
// если такой элемент уже есть

if (find(A, A + i, A[i]) != (A + i))

i--; // взаимно уничтожится с i++

}

}
void ShowArray(int A[], int n)

{

for (int i = 0; i < n; i++)

cout << " " << A[i];

cout << endl;

}
void main()

{

setlocale(LC_CTYPE, "rus");

SetColor(white_color);
int n;

cout << "Введите число случайных ключей: ";

cin >> n;

int * A = new int[n];

RandomArr(A, n); // рандомом заполняем массив

cout << "Случайный массив: ";

SetColor(cyan_color); // чтобы вывести цветом

ShowArray(A, n); // выводим массив

SetColor(white_color);
// формируем дерево по массиву ключей

Avlka MEGADEREVCE(A, n);

cout << "Авлка:\n";

SetColor(cyan_color);

MEGADEREVCE.PrintTree(); // выводим дерево

SetColor(white_color);
delete[] A;
// добавляем ключи в дерево, пока не надоест

while (true)

{

int key;

cout << "Введите добавляемый ключ (или 0 - для выхода): ";

SetColor(cyan_color);

cin >> key;

if (key == 0) break;

SetColor(white_color);
// вернет false при дублировании ключей

if (MEGADEREVCE.Vstavka(key) == false)

cout << "Такой ключ уже есть\n";

else // при недублировании ключей

{

cout << "Авлка:\n";

SetColor(cyan_color);

MEGADEREVCE.PrintTree(); // покажем обновленное дерево

SetColor(white_color);

}

}

}

5.3. Демонстрация программы


Сформируем дерево по случайным ключам.



Обозначения: L - левое поддерево, R - правое поддерево, bfactor - разность высоты правого и левого поддерева (у АВЛ-дерева может быть только -1, 0 или 1).

Пример вставки, когда балансировка не нужна:



Заметим, что выполнена корректировка показателей сбалансированности.



Продемонстрируем вставку для случая, когда баланс нарушится. Если вставить ключ 222 без балансировки, у поддерева с корнем 459 высота левого поддерева станет 2, а правого останется 0, т.е. показатель = -2.



При вставке 222 программа осуществила балансировку:



Еще несколько примеров вставки:







Примеры попыток добавить существующий ключ:



Тестирование показывает, что программа корректно работает, даже когда при вставке нарушается допустимый баланс поддеревьев корня.



6. ЛАБОРАТОРНАЯ РАБОТА №6

6.1. Задание


Написать процедуру обхода графа G (выдачи на печать всех его вершин).

6.2. Решение


Существуют два базовых варианта – обход в глубину (DFS) и в ширину (BFS). Идея DFS заключается в том, что мы двигаемся от начальной вершины в определенном направлении (по определенному пути) до тех пор, пока можем. Если далее двигаться некуда («тупик» или все доступные вершины уже посещены), то мы возвращаемся назад (к точке разветвления или расхождения путей) и идем по другому маршруту. BFS подразумевает посещение соседей стартовой вершины, затем посещение соседей этих соседей и т.д.

Для реализации DFS/BFS мы поддерживаем список открытых вершин – которые предстоит проверить, и массив флагов, указывающих, является ли каждая вершина посещенной. Изначально список открытых вершин содержит только начальную. Далее, для каждой вершины из списка открытых вершин выполняется раскрытие – сама вершина считается посещенной и извлекается из списка, а еще не посещенные смежные с ней вершины заносятся в список открытых. Если извлечение из списка открытых и добавление в список – с одного конца, имеем поиск в глубину (в данном случае его нерекурсивный способ), если с разных концов – в ширину. При наличии нескольких компонент связности такой обход нужно выполнить отдельно для каждой.

#include

#include

#include

#include
#define MAXN 20

#define FAIL -1
using namespace std;
// чтение матрицы смежности из файла

int ReadMatrix(char FileName[], bool A[MAXN][MAXN])

{

ifstream file(FileName, ios::in);
int n, cur;

file >> n; // читаем число вершин
// читаем матрицу

for (int i = 0; i < n; i++)

for (int j = 0; j < n; j++)

{

file >> cur;

if (cur == 0) A[i][j] = false;

else A[i][j] = true;

}
file.close();

return n;

}
// поиск первой непосещённой вершины, начиная со start-ой

int IndexOfNotVisit(bool Visited[], int start, int n)

{

for (int i = 0; i < n; i++)

if (Visited[i] == false) return i;

return FAIL;

}
void InitBoolArr(bool Arr[], int n)

{

for (int i = 0; i < n; i++)

Arr[i] = false;

}
struct Node // узел списка вершин

{

int item; // номер вершины

Node * next; // указатель на следующий элемент

Node(int item)

{

this->item = item;

this->next = NULL;

}

};
class List // список

{

Node * head, *tail;

public:

List() { head = NULL; }
// ToHead = true - вставка в голову,

// ToHead = false - вставка в хвост

void Add(int item, bool ToHead)

{

if (head == NULL) // если список пустой

{

head = new Node(item);
// единственный узел одновременно и голова, и хвост списка

tail = head;

return;

}
if (ToHead == true)

{

Node * p = new Node(item);

p->next = head;

head = p;

}

else

{

tail->next = new Node(item);

tail = tail->next;

}

}
// извлечение содержимого головы (с удалением головы)

int ExtractHead()

{

if (head == NULL) return FAIL;
Node * q = head->next;

int extracted = head->item; // запомнить, что было в голове

delete head; // удалить голову

head = q; // кто был следующим за головой теперь голова

return extracted;

}
bool Contains(int item) // поиск элемента item

{

Node * cur = head;

while (cur)

{

if (cur->item == item) return true;

cur = cur->next;

}

return false;

}
List()



{

Node * p = head, *q;

while (p)

{

q = p->next;

delete p;

p = q;

}

}
friend ostream & operator << (ostream & os, List & spisok);

};
ostream & operator << (ostream & os, List & spisok)

{

Node * cur = spisok.head;

while (cur)

{

os << (cur->item + 1) << " ";

cur = cur->next;

}

return os;

}


// процедура раскрытия вершины node

void Discover(List * Opened, bool A[MAXN][MAXN], int n, int node, bool IsDepth, bool Visited[])

{

// цикл по node-ой строке матрицы смежности

for (int k = 0; k < n; k++)

{

int i = (IsDepth == false) ? k : (n - k - 1);
// если есть связь (node, i)

if (A[node][i] == true)

{

// если i-ая вершина не посещена и отсутствует

// в списке открытых

if (Visited[i] == false && Opened->Contains(i) == false)

{

// вносим вершину в список открытых (для поиска в глубину - в голову списка, для поиска в ширину - в хвост)

Opened->Add(i, IsDepth);

}

}

}

}
// обход компоненты связности

void Traverse(bool A[MAXN][MAXN], int n, bool IsDepth, int start, bool Visited[], List * results)

{

List Opened; // открытые вершины
// вносим стартовую вершину в открытые

Opened.Add(start, IsDepth);
while (1)

{

// извлекаем головной элемент из списка открытых

int node = Opened.ExtractHead();
// если оказалось, что список открытых вершин пустой

if (node == FAIL) break;
// добавляем извлеченный элемент в список результатов

results->Add(node, false);
// помечаем node как посещённую

Visited[node] = true;
// используем процедуру раскрытия для node

Discover(&Opened, A, n, node, IsDepth, Visited);

}

}
// основная функция обхода

List * Traverse(bool A[MAXN][MAXN], int n, bool IsDepth)

{

List * results = new List;
// создаем массив для хранения информации о том, какие вершины посещали

bool Visited[MAXN];
// пока что заполняем его значениями false

InitBoolArr(Visited, n);
int node = 0;
// цикл вызовов вспомогательной функции -

// свой вызов на каждую компоненту связности

while (node != FAIL)

{

Traverse(A, n, IsDepth, node, Visited, results);
// проверим, все ли вершины посещены, и выдадим индекс

// первой не посещённой (если такие ещё есть)

node = IndexOfNotVisit(Visited, node + 1, n);

}
return results;

}
void main()

{

setlocale(LC_ALL, "rus");
bool A[MAXN][MAXN];

char FileName[30];

cout << "Введите имя файла: ";

cin >> FileName;

int n = ReadMatrix(FileName, A);
List * spisok = Traverse(A, n, true);

cout << "Обход в глубину: " << (*spisok) << "\n";

delete spisok;
spisok = Traverse(A, n, false);
cout << "Обход в ширину: " << (*spisok) << "\n";

delete spisok;

_getch();

}

6.3. Демонстрация программы


Тест для дерева:



Вид матрицы смежности в файле и самой программы:



Тест для графа с двумя компонентами связности, каждая из которых содержит циклы (тем самым мы проверяем, правильно ли учитываются флаги посещения вершин в функции раскрытия):