ЛАБОРАТОРНАЯ РАБОТА 1 АЛГОРИТМЫ СОРТИРОВКИ Цель лабораторной ознакомится с различными методами сортировки данных Под сортировкой понимают процесс перестановки объектов данного множества в определенном порядке. Цель сортировки - облегчить последующий поиск элементов в отсортированном множестве. В этом смысле сортировка присутствует почти во всех задачах обработки информации. С сортировкой связаны многие фундаментальные приемы построения алгоритмов, которые и будут нас интересовать в первую очередь. В частности, сортировка является идеальным примером огромного разнообразия алгоритмов, выполняющих одну и ту же задачу, многие из которых в некотором смысле оптимальные, а большинство имеет какие-либо преимущества по сравнению с остальными. Поэтому на примере сортировки мы убеждаемся в необходимости сравнительного анализа алгоритмов. Зависимость выбора алгоритмов от структуры данных - явление довольно частое, а в случае сортировки она настолько сильна, что методы сортировки обычно разделяются на две категории: сортировка массивов (внутренняя сортировка) сортировка файлов (внешняя сортировка). ПОСТАНОВКА ЗАДАЧИ a1 , a 2 ,..., a n ДАНО ai1 , ai 2 ,... ain ТРЕБУЕТСЯ ai1 ai 2 ... ain СВЯЗЬ и последовательность является перестановкой исходной последовательности. Основное требование к методам внутренней сортировки - экономное использование памяти. Это означает, что переупорядочивание элементов надо выполнять на том же месте. Методы внутренней сортировки можно разбить на четыре основных класса в зависимости от лежащего в их основе приема: сортировка включением(вставкой), сортировка выбором, сортировка обменом, разделением. СОРТИРОВКА ВКЛЮЧЕНИЕМ. Этот метод состоит в том, что на каждом шаге берут i-ый элемент последовательности и передают его в готовую отсортированную часть последовательность, вставляя его на свое место. Алгоритм сортировки включениями выглядит следующим образом: FOR I := 2 TO N DO BEGIN X := a[I]; <вставить X на подходящее место в a[1],a[2],...,a[I]> END СОРТИРОВКА ВЫБОРОМ. Этот метод основан на следующем правиле. Выбирается минимальный (максимальный) элемент последовательности и обменивается с первым элементом (элементом) последовательности. Очевидно, один элемент при этом встанет на свое место в отсортированной части последовательности. Далее все выше изложенное надо повторить в не отсортированной части последовательности и т.д. FOR I = 1 TO N-1 DO BEGIN <присвоить K индекс наименьшего элемента из a[I]...a[N]> <поменять местами a[I] и a[K]> END СОРТИРОВКА ОБМЕНОМ. Алгоритм обмена основан на принципе сравнения и обмена пары соседних элементов до тех пор, пока не будут отсортированы все элементы. В качестве примера рассмотрим сортировку методом пузырька. FOR I:= 2 TO N DO FOR J:= N DOWNTO I DO IF a[J-1] > a[J] THEN BEGIN X := a[J-1]; a[J-1] := a[J]; a[J] := X END СОРТИРОВКА РАЗДЕЛЕНИЕМ. Алгоритм разделением основан на разбиении последовательности на две подпоследовательности по некоторому правилу. При этом каждая из них может не являться упорядоченной, но последовательное применение указанного правила приводит к упорядоченности последовательности. Примером этого класса алгоритмов является алгоритм быстрой сортировки. Procedure quicksort(S); begin if <S содержит один элемент> then <возвратить S> else begin <выбрать произвольный элемент a из S>; <пусть S1 ,S2 и S3 - последовательности элементов из S, соответственно меньших, равных и больших a>; <возвратить quicksort(S1), затем S2,, затем quicksort(S3) > end end Внешняя сортировка, т.е. сортировка данных, находящихся на внешних запоминающих устройствах, имеет свои особенности. Существенную долю времени в этих сортировках тратится на обмен информации с внешним запоминающим устройством, поэтому нужны алгоритмы, которые минимизируют число таких операций. Оперативная память имеет ограниченные размеры и поэтому в каждый момент времени может быть доступна только часть данных. Рассмотрим один из алгоритмов внешней сортировки. СОРТИРОВКА СЛИЯНИЕМ. Главная идея, которая лежит в основе этой сортировки это представлении файла в виде постепенно увеличивающихся серий, т.е. упорядоченных подпоследовательностей. Если есть, по крайней мере, два файла и число серий в них равно или отличается на единицу, то последовательным слиянием отсортированных серий в новый файл можно уменьшить количество серий, по крайней мере, в два раза. ЗАДАНИЕ 1. Используя указанную ниже литературу, изучить и реализовать следующие сортировки: 1. 2. 3. 4. 5. 6. 7. Простой вставкой. Пузырьковая сортировка. Простым выбором. Пирамидальная сортировка. Быстрая рекурсивная сортировка. Быстрая сортировка с использованием стека. Файловая сортировка естественным слиянием. ЗАДАНИЕ 2. Провести анализ сложности алгоритмов сортировок 1 – 6 из задания 1 , для этого включить в алгоритм подсчет числа базовых операций ( сравнения и обмена) и вычисление времени работы программы на данном массиве. ВАРИАНТЫ ДОМАШНИХ ЗАДАНИЙ Изучить, используя литературу , и реализовать указанный ниже метод сортировки, оценить его сложность и построить график эффективности программы. ВАРИАНТ 1. “Карманная” сортировка [2] ВАРИАНТ 2. Поразрядная сортировка [2] ВАРИАНТ 3. Сортировка Шелла. [2] ВАРИАНТ 4. Сортировка двухпутевым слиянием [3]. ВАРИАНТ 5. Сортировка связных списков слиянием сверху вниз[3]. ВАРИАНТ 6. Восходящая сортировка связных списков слиянием [3]. ВАРИАНТ 7. Быстрая сортировка с разделением на три части[3]. ВАРИАНТ 8. Индексная сортировка [3] ВАРИАНТ 9. Сортировка бинарными включениями.[1]. ВАРИАНТ 10.Шейкер-сортировка [1]. ВАРИАНТ 11.Сортировка связных списков [3] ВАРИАНТ 12. Метод распределяющего подсчета [3]. ВАРИАНТ 13.Метод разделения с вычислением медианы трех элементов [3]. ВАРИАНТ 14.Поразрядная сортировка [3]. DFHBFYN ЛАБОРАТОРНАЯ РАБОТА 2 АЛГОРИТМЫ ОБРАБОТКИ МНОЖЕСТВ Цель лабораторной работы освоение программирования операций над множествами. Под множеством понимается неупорядоченная совокупность различных элементов. Множество, число элементов которого конечно, называется конечным множеством. При программировании задач над множествами естественно рассматривать конечные множества. Число элементов множества A называется его мощностью и обозначается через |A|. Множество можно задать перечислением его элементов. Например, A = {1, 3, 4, 5, 7}. Основными операциями над множествами являются изучаемые в школе операции объединения A и пересечения , имеющие следующую интерпретацию B {x | x A ИЛИ x B} , A B {x | x A И x B} . Здесь использовано другой способ задания множества – описание свойств, которыми обладают элементы множества. Операция дополнение множества требует введения понятия универсального множества. При решении многих задач рассматриваются только множества, являющиеся подмножествами некоторого множества U. Это множество U называется универсальным множеством. Универсальное множество определяется классом задач и может иметь малую мощность. Например, в качестве универсального множества можно рассматривать множество из двух элементов {0, 1}. Дополнением множества A, являющегося подмножеством универсального множества U, является множество A {x | x U И x A} . Булеаном множества A называется множество всех подмножеств множества A. Булеан множества A обозначают через 2 . Это объясняется равенством | 2 | 2 A A | A| . Для доказательства этого равенства подмножеству A1 множества A ставится в соответствие двоичный набор длины |A|. В этом наборе i-я компонента равна 1 тогда и только тогда, когда i-й элемент множества A является элементом множества A1. Нетрудно проверить, что различным подмножествам соответствуют различные наборы из 0 и 1. Напомним, что k число двоичных наборов длины k равно 2 . При выполнении лабораторной работы в качестве универсального множества будем рассматривать множество U = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}. Внутримашинным представлением множества A = {i1, i2, , ik} считаем целое число nA (типа int), единичными битами которого являются только биты с номерами i1, i2, , ik. Например, внутримашинным представлением множества {1, 3, 8} является число 21 + 23 + 28 = 265. При таком внутримашинном представлении множеств операции над последними выполняются на компьютере с использованием очень быстрых побитовых операций; при этом, также, экономится память. Заметим, что в более новом, чем Паскаль, языке программирования Си для обозначения побитовых операций & и | (дизъюнкция) используется один символ, а для обозначения логических операций И и ИЛИ применяют два символа && и ||. Пусть nA и nB – внутримашинные представления множеств A и B. Нетрудно проверить, что внутримашинным представлением множества A B (множеств A B и A ) является число nA|nB (числа nA&nB и (~nA)&4095). Напомним, что при выполнении побитовой операции инверсия ~nA в двоичном представлении числа nA 0 заменяется на 1, а 1 заменяется на 0. При этом биты с номерами 12, 13, 14 и 15 станут единичными. Для устранения этого выполняем операцию побитового умножения на число 4095 = 2 12 – 1, которое является внутримашинным представлением нашего универсального множества U = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}. Основной целью лабораторной работы является решение теоретико-множественных уравнений типа A X B , где A и B – заданные множества. Операция заменена операциями может быть , \. Операция \ имеет следующую интерпретацию: A \ B = A B. Отметим, что используется и операция симметрическая разность A B множеств A и B, результатом которой является множество всех элементов, принадлежащих либо множеству A, либо множеству B. Рассмотрим решение уравнения A X B. Следует осторожно подходить к преобразованию теоретико-множественных равенств, не перенося на них целиком свойства этих преобразований на множестве вещественных чисел. Так из числового равенства a +c = b + c при любых a, b и c следует равенство a + b. Легко проверить, что теоретико-множественное равенство A U B U , где U – универсальное множество, верно при любых множествах A и B (являющихся подмножествами множества U). Нетрудно проверить, что уравнение A X B имеет решение при B A . В терминах внутримашинных представлений множеств A и B это условие эквивалентно истинности выражения nA & nB = = nA . Нарисовав и проанализировав диаграмму Эйлера-Венна, делаем заключение, что (при выполнении условия B A ) уравнение A X B имеет 2|A| решений вида X = (B \ A) M, где M – произвольное подмножество множества A. Таким образом, при решении теоретико-множественных уравнений может возникнуть задача нахождения всех подмножеств заданного множества. Рассмотрим одно из возможных решений этой задачи. Множеству A сопоставим массив char msA[kA], где kA = |A|. Элемент msA[i], 0 i kA , является i-м элементом множества A. Результат (записанные с новой строки подмножества множества A) будем помещать в символьный массив mout. Функция sprintf() аналогична функции printf(); она записывает форматированные данные в символьный массив, который является первым аргументом этой функции. Символьный массив tmp используется для формирования элементов текущего подмножества. Функция strcat(char *str1, char *str2) добавляет к строке str1 строку str2. Приведем фрагмент программы, реализующей эту задачу. int NA = 1 << kA; for(i=0; i<NA; i++) { sprintf(tmp, "{"); /* Начало записи i-го подмножества – добавление открывающей фигурной скобки */ strcat(mout, tmp); /* Конкатенация (слияние) строк; к строке mout добавляется строка tmp*/ /* Формирование элементов i-го подмножества*/ for(j=0; j<kA; j++) if(i&(1<<j)) /* Если j-й бит числа i равен 1*/ { sprintf(tmp,"%d, ",msA[j]); strcat(mout, tmp); } mout[strlen(mout)-1]='}'; /* конец записи i-го подмножества – добавление закрывающей фигурной скобки */ /*функция strlen(ms) возвращает длину строки ms*/ sprintf(tmp,"\n"); /* Добавление символа новой строки*/ strcat(mout, tmp); } Переходим теперь к описанию программы решения теоретико-множественного уравнения A X B. Вначале опишем форматы входного и выходного файлов. Информация об исполнителе и теме работы (ФИО, группа, ДМ, лаб.1) расположена в первой строке входного файла. Во второй и четвертой строках входного файла записаны мощности множеств A и B, соответственно. В третьей и пятой строках входного файла через запятую записаны элементы множеств A и B, соответственно. Пример входного файла. Иванов И.И., группа ЗИ–31, лаб. 1 6 1, 3, 4, 6, 9, 10 8 0, 1, 3, 4, 6, 9, 10, 11 Необязательные пробелы вставлены для проверки работы программы. Для проверки выполнения программой условия существования решений пятую строку этого замените строкой «0, 1, 4, 6, 7, 9, 10, 11». Первые пять строк выходного файла совпадают с входным файлом. Затем идет строчка «Решениями уравнения A X B являются следующие множества:». Далее идут описания решений (множеств); каждое с новой строки. Приводим тексты программы. Отметим, что для большей универсальности использованы аргументы командной строки argc (число аргументов командной строки) и argv (массив указателей на аргументы командной строки). Указатель argv[0] является адресом начала записи имени программы. В нашем случае argv[1] является адресом начала записи имени входного файла, а argv[2] является адресом начала записи имени выходного файла. /*Решение уравнения A X B */ #include<stdio.h> #include<stdlib.h> #include<conio.h> #include<io.h>#include<string.h> #include<alloc.h> void main(int argc, char* argv[]) {char msA[12], ms[100], tmp[5]; char* m_in, *mout; int * mnX; int i, j, r, kA, nA, kB, nB, MA, nX0; FILE *in, *out; if( (in = fopen(argv[1], "r")) == NULL ) { puts("Net vhodnogo faila!"); exit(0);} m_in = (char*) malloc(400); /* Во входном файле 5 строк*/ /* в первой строке нет информации для уравнения*/ fgets(ms, 100, in); strcat(m_in, ms); fgets(ms, 100, in); strcat(m_in, ms); kA = atoi(ms); /*по записи числа получаем его внутримашинное представление*/ fgets(ms, 100, in); /*из файла считываем 3-ю строку, содержащую запись множества A*/ strcat(m_in, ms); /* r – позиция в ms*/ r = 0; while (ms[r] != '{') r++; r++; msA[0] = atoi(ms+r); nA = 1<<msA[0]; for(i = 1; i <kA; i++) { while(ms[r]!=',') r++; r++;msA[i] = atoi(ms+r); nA |= 1<<msA[i]; } /*Для отладки программы; после отладки закомментировать*/ printf(“Множество A: “); for(i=0; i < kA; i++) printf(“%d “, msA[i]); printf("nA = %d\n", nA); /* Считывание и обработка множества B */ /*Считываем 4-ю строку входного файла*/ fgets(ms, 100, in); strcat(m_in, ms); kB = atoi(ms); fgets(ms, 100, in); /*Из файла считываем 5-ю строку, содержащую запись множества B*/ strcat(m_in, ms); /*Теперь в m_in весь входной файл*/ r = 0; while (ms[r] != '{') r++; r++; nB = 1<< atoi(ms+r); нужен*/ /* символьный массив для множества B в нашей задаче не for(i = 1; i <kB; i++) { while(ms[r]!=',') r++; r++;nB |= 1<< atoi(ms+r); } /*Две строки – для отладки программы; после отладки закомментировать*/ printf(“Множество B: “); printf("nB = %d\n", nB); fclose(in); /*Проверка существования решений*/ if(nA & nB != nA) {puts(“Net reshenyi!”); exit(0);} nX0 = nB & (~nA & 4095); /* X0 = B \ A */ /* Формируем массив mnX */ MA = 1 << kA; mnX = (int*) malloc(2*MA); /* 2 – sizeof(int)*/ for(i=0; i < MA; i++) { mnX[i] = 0; for(j=0; j<kA; j++ if(i&(1<<j)) /* Если j-й бит числа i равен 1*/ mnX[i] |= 1 << msA[j]; mnX[i] |= nX0; } /* Формирование символьного массива mout для выходного файла с использованием массива mnX внутримашинных представлений решений нашей задачи */ out=fopen(argv[2],"w"); mout=(char*) malloc(strlen(m_in) + MA*(4*kA + 4); /*Оценка длины массива mout. Функция strlen(ms) возвращает длину строки ms*/ strcat(mout, m_in); strcat(mout, “Решениями уравнения A X B являются следующие множества:”); for(i=0; i<MA; i++) { sprintf(tmp, "{"); /* Начало записи i-го подмножества*/ strcat(mout, tmp); /* Конкатенация (слияние) строк; к строке mout добавляется строка tmp*/ /* Формирование элементов i-го подмножества*/ for(j=0; j<12; j++) if(mnX[i]&(1<<j)) /* Если j-й бит внутримашинного представления i-го решения равен 1*/ { sprintf(tmp,"%d, ", j); strcat(mout, tmp); } mout[strlen(mout)-1]='}'; /* конец записи i-го решения*/ /*функция strlen(ms) возвращает длину строки ms*/ sprintf(tmp,"\n"); /* Добавление символа новой строки*/ strcat(mout, tmp); } /* Формирование выходного файла*/ write(fileno(out),mout,strlen(mout)); /* Функция write() записывает в файл символьный массив. Она работает с идентификатором файла, который получается из FILE* с использованием функции fileno().*/ puts("End"); /* Для задержки на экране строки "End" */ gets(ms); fclose(out); } Пример начала выходного файла, соответствующего приведенному выше примеру входного файла. Иванов И.И., группа ЗИ–31, лаб. 1 6 1, 3, 4, 6, 9, 10 8 0, 1, 3, 4, 6, 9, 10, 11 Решениями уравнения A {0, 11} {0, 1, 11} {0, 3, 11} {0, 1, 3, 11} {0, 4, 11} X B являются следующие множества: ………….. В других вариантах заданий даны уравнения A X B, A\ X B и X \ A B. Проверьте справедливость следующих утверждений: 1. При выполнении условия A B уравнение A вида X = B 2. X B имеет 212 –|A| решений M, где M – произвольное подмножество множества A При выполнении условия A B уравнение A \ X B имеет 212 –|A| решений вида X = ( A \ B) M , где M – произвольное подмножество множества A . 3. При выполнении условия A B уравнение X \ A B имеет 2|A| решений вида X=B M, где M – произвольное подмножество множества A. ЛАБОРАТОРНАЯ РАБОТА 3 АБСТРАКТНЫЕ ТИПЫ ДАННЫХ Хотя термины тип данных, структура данных и абстрактный тип данных звучат похоже, но имеют различный смысл. В языках программирования тип данных переменной обозначает множество значений, которые может принимать эта переменная, и набор операций, которые могут применяться к переменным данного типа. Набор базовых типов данных отличается в различных языках: в языке Pascal это типы целых и действительных чисел, булев тип и символьный. Структура данных - это составные типы данных, построенные на основе базовых типов. Правила конструирования структур данных в разных языках программирования тоже различны: в языке Pascal это массивы, строки, множества, записи. Абстрактный тип данных- это математическая модель и различные операторы, определенные в рамках этой модели. В этой лабораторной работе будут рассмотрены основные абстрактные типы данных: списки, деревья, графы. ЧАСТЬ 1. СПИСКИ. Списком a1a2,a3,...,ak называют конечную упорядоченную последовательность элементов. В алгоритмах обработки информации часто приходится встречаться с представлением списков и операциями над ними. Рассмотрим различные способы представления списков и различные операции. Можно выделить следующие операции над списками: получить доступ к K-му элементу списка; включить новый элемент в список; исключить элемент из списка; объединить несколько списков в один; разбить список на несколько списков; определить число элементов в списке; выполнить сортировку списка; сделать копию списка. В приложениях редко требуется выполнение всех перечисленных выше операций. Существует много способов представления списков в зависимости от класса операций, которые необходимо выполнять наиболее часто. Очень часто встречаются списки, в которых включение, исключение или доступ к значениям почти всегда производятся в первом или последнем элементе, они имеют специальные названия. Стек - список, в котором все включения и исключения делаются в одном конце списка. Очередь - список, в котором все включения делаются на одном конце, а все исключения на другом. Дек - список, в котором все включения и исключения делаются на обоих концах. Очевидно, что простейшим представлением списка является представление его в последовательных ячейках памяти, т.е. в виде массива, при этом выделение памяти под список осуществляется до начала выполнения программы, т.е. статически. При этом такие операции как включение и исключение оказываются дорогостоящими, т.к. приходится передвигать элементы списка в памяти компьютера. Однако при этом такие операции как доступ к k -му элементу списка или получить копию списка можно осуществить легко. Рассмотрим два способа реализации списка посредством массива и с помощью указателей. ЗАДАНИЕ 1. Реализовать перечисленные выше операции над списком, используя оба способа реализации списка. ЗАДАНИЕ 2. Рассмотрим списки с ограниченным доступом к элементам списка такие как стек и очередь. Реализовать следующие примитивные операции работы со стеком и очередью, используя оба способа представления списка: сделать_пустым(var s: стек элементов типа T) добавить(t:T;var s: стек элементов типа T) взять(var t:T;var s: стек элементов типа T) пуст(var s: стек элементов типа T): Boolean вершина(var s: стек элементов типа T): T ДОПОЛНИТЕЛЬНЫЕ ЗАДАНИЯ: 1. Операции над многочленами: дифференцирование сложение умножение деление 2. Проверка правильности расстановки скобок (, ), [, ], {, }в арифметическом выражении (с использованием стека). 3. реализация двухсвязного списка. ЧАСТЬ 2. ДЕРЕВЬЯ Бинарное дерево - это конечное множество элементов, которое либо пусто, либо содержит один элемент, называемый корнем дерева, а остальные элементы множества делятся на два непересекающихся подмножества, каждое из которых само является бинарным деревом. Эти подмножества называются левым и правым поддеревьями исходного дерева. Каждый элемент исходного бинарного дерева называется узлом. На рис.1 представлено схематическое изображение бинарного дерева. Узел1 Узел2 Узел4 Узел3 Узел 5 Узел6 РИС. 1. Эту нелинейную структуру можно представить в виде массива, т.е. статически (см. Лабораторную работу № 1). Однако наиболее прозрачным способом представления бинарного дерева является связанный список. На рис. 2 представлено схематическое изображение бинарного дерева в виде связанного списка. Root Llink Node1 Rlink Llink Node2 Rlink nil Node4 nil nil адрес первого элемента дерева nil Node5 Node3 Rlink nil nil Node6 nil РИС.2. ПРИМЕР 1. Программы, создающей бинарное дерево из шести узлов с упорядоченными ключами (key) и распечатывающей ключи в порядке прохода по узлам дерева в глубину. Программа создания дерева бинарного поиска печать его глубину с помощью стека и в ширину с помощью очереди. Стек и очередь представлены массивом. program tree; type ref = ^node; node = record key:integer; lnext:ref; rnext:ref end; var p,q,root:ref; s:array[1..5] of ref;{Стек} o:array[1..5] of ref; {Очередь} n,x,i,t,f,l:integer; procedure build_tree; function newnode(x:integer):ref; var p1:ref; begin new(p1); p1^.key:=x; p1^.lnext:=nil; p1^.rnext:=nil; newnode:=p1 end; procedure add_node(var r1:ref; k1:integer); var p1,q1:ref; begin{5} if r1=nil then begin {Создание первой вершины} r1:=newnode(k1); {Запоминание корня дерева}end else begin{4} p1:=r1; while (p1<> nil) and (k1<>p1^.key) do{Поиск места вставки еще одной вершины} begin{3} q1:=p1; if k1=p1^.key then writeln('значение присутствует в дереве') else begin{2} if k1 < p1^.key then p1:=p1^.lnext else p1:=p1^.rnext; end;{2}end;{3} if p1=nil then begin{1} {Вставка вершины} if k1< q1^.key then q1^.lnext:=newnode(k1) else q1^.rnext:=newnode(k1); end;{1} end;{4} end; {5} begin root:=nil; writeln('введите количество вершин дерева'); readln(n); for i:=1 to n do begin writeln('введите ключ'); readln(x); add_node(root,x); end; end; procedure print1; begin writeln('Проход дерева сверху-вниз================'); t:=1; s[t]:=root; while t<>0 do begin p:=s[t]; t:=t-1; write(p^.key,' '); if p^.rnext <> nil then begin t:=t+1; s[t]:=p^.rnext end; if p^.lnext <> nil then begin t:=t+1; s[t]:=p^.lnext end; end; writeln; end; begin build_tree; print1; writeln;} writeln('проход по дереву в ширину'); f:=1; l:=1; o[l]:= root; while f <= l do begin p:=o[f]; f:=f+1; write(p^.key,' '); if p^.lnext <> nil then begin l:=l+1; o[l]:=p^.lnext end; if p^.rnext <> nil then begin l:=l+1; o[l]:=p^.rnext end; end; writeln; end. ЗАДАНИЕ 1. Написать программу создания бинарного дерева, содержащего следующую информацию: - код города; - название города; - адрес. Процесс добавления новых узлов прекратить при вводе кода города равного 0. ЗАДАНИЕ 2. Организовать проход по дереву в глубину с использованием стека. Стек реализовать связным списком. ЗАДАНИЕ 3. Организовать проход по дереву в Ширину с использованием очереди. Очередь реализовать связным списком. ЗАДАНИЕ 4. Написать процедуры добавления и удаления вершины из дерева. ВАРИАНТЫ ДОМАШНИХ ЗАДАНИЙ. Реализовать ВАРИАНТ 1. Распечатать концевые узлы дерева. ВАРИАНТ 2. Распечатать внутренние узлы дерева. ВАРИАНТ 3.. Обход дерева в глубину рекурсивный. ВАРИАНТ 4.. Обратный обход графа с использованием со стеком. ВАРИАНТ 5. Обратный обход графа рекурсивный. ВАРИАНТ 6.. Симметричный обход графа с использованием со стеком. ВАРИАНТ 7. Симметричный обход графа рекурсивный. ВАРИАНТ 8. Определение высоты дерева. ВАРИАНТ 9. Определение самого левого минимального ключа в дереве поиска. ВАРИАНТ 10.Определение максимального ключа в дереве поиска ЧАСТЬ 3 ГРАФЫ. ЦЕЛЬ. Дать представление об основных задачах на графах. В настоящее время возросла роль графовых моделей в различных практических приложениях таких, как автоматизированные системы управления, экспертные системы, системы искусственного интеллекта и т.п. Графом называют систему объектов G (V , E ) , где V (v1 , v 2 ,..., v m ) множество вершин, а E {e1 , e2 ,..., en } - множество ребер и ek (v ki , vk j ) . Если пара (v ki , vk j ) .упорядочена, то граф называют ориентированным, в противном случае граф - неориентированный или просто граф. Например, 1 a c V = { 1,2,З,4,5 } E = { a = (1,2), b = (2,З), 2 - b d 4 3 f e c = (1,З), d = (2,4), e = (4,5) f = (З,5) } 5 Маршрут из вершины vi в v j это чередующаяся последовательность вершин и ребер, начинающаяся в вершине vi и заканчивающаяся в вершине v j и в которой любая пара соседних элементов инцидентна ( вершина v и ребро e инцидентны, если e = (v,w) или e = (v,w)). ЗАДАНИЕ 1. Написать программу представления графа в Паскале, для следующих способов задания графа таблицей смежности таблицей инциденций вершинной окрестностью ЗАДАНИЕ 2. Написать следующие процедуры (функции) обработки графа добавить ребро изъять ребро добавить вершину изъять вершину ВАРИАНТЫ ДОМАШНИХ ЗАДАНИЙ ЗАДАНИЕ 1. Написать программу поиска эйлеровой цепи и эйлеровых циклов. ЗАДАНИЕ 2. Гамильтонова цепь - маршрут, в котором содержатся все вершины графа ровно один раз. Написать программу поиска гамильтоновой цепи в графе. ЗАДАНИЕ 3. Гамильтонов цикл - гамильтонова цепь, у которой начальная и конечная вершины совпадают. Написать программу поиска гамильтонова цикла в графе. ЗАДАНИЕ 4. В графе, ребрам которого приписаны веса, написать программу поиска пути минимального веса, соединяющий заданную пару вершин. Вес пути равен сумме весов ребер, входящих в этот путь. ЗАДАНИЕ 5. Множество вершин неориентированного графа G называется внешне устойчивым, если для любой вершины v1 из множества V(G)\ найдется вершина v 2 из такая, что ( v1 , v 2 ) - ребро графа G. Написать программу поиска наименьшего внешне устойчивого множества графа. ЗАДАНИЕ 6. Множество вершин неориентированного графа G называется внутренне устойчивым, если для любой пары вершины v1 и v 2 из не существует ребра ( v1 , v 2 ) в графе G. Написать программу поиска наибольшего внутренне устойчивого множества графа. ЗАДАНИЕ 7. Построить остов в неориентированном связанном графе. Остовом называют дерево, построенное из ребер графа и содержащее все его вершины. ЗАДАНИЕ 8. В графе, ребрам которого приписаны веса, написать программу поиска пути максимального веса, соединяющий заданную пару вершин. Вес пути равен сумме весов ребер, входящих в этот путь. ЗАДАНИЕ 9. Обход графа в глубину ЗАДАНИЕ 10. Обход графа в ширину ЗАДАНИЕ 11. Нахождение центра графа. ЗАДАНИЕ 12. Нахождение минимального реберного покрытия графа. ЗАДАНИЕ 13. Нахождение транзитивного замыкания графа.