![](/user_photo/2706_HbeT2.jpg)
- •1.1. Элементы языка программирования
- •Основные правила записи программы:
- •1.2. Алфавит языка
- •1.3. Лексемы
- •1.4. Концепция данных
- •2.2. Операции
- •2.2.1. Арифметические операции
- •2.2.2. Операции присваивания
- •2.2.3. Операции отношения
- •2.2.4. Логические операции
- •2.2.5. Поразрядные операции
- •2.2.6. Вычисление выражений
- •3. Структурное программирование
- •3.1. Общая характеристика операторов
- •3.2. Оператор-выражение
- •3.3. Условный оператор
- •3.4. Составной оператор
- •3.5. Операторы для программирования циклов
- •3.5.1. Оператор цикла for
- •3.5.2. Оператор цикла while
- •3.5.3. Оператор цикла do while
- •3.5.4. Оператор break
- •3.5.5. Оператор continue
- •3.6. Оператор goto
- •3.7. Пустой оператор
- •3.8. Оператор switch
- •3.9. Оператор return
- •4. Массивы
- •4.1. Объявление массива
- •4.2. Обращение к элементам массива
- •4.3. Типовые алгоритмы работы с массивами
- •4.4. Многомерные массивы
- •5. Строки
- •5.1. Объявление строки
- •5.2. Посимвольная обработка строк
- •5.3. Ввод строк
- •5.4. Библиотечные функции для работы с текстом
- •6. Указатели
- •6.1. Объявление указателей
- •6.2. Операции над указателями
- •6.3. Связь между указателями и массивами
- •6.4. Функция strtok для выделения лексем из текста
- •6.5. Динамические массивы
- •7. Структуры и объединения
- •7.1. Объявление структуры
- •Компонент структуры может быть любого типа, кроме типа объявляемой структуры.
- •7.2. Операции над структурами
- •7.3. Объявление объединения
- •8. Модульное программирование
- •8.1. Нисходящее проектирование и программирование
- •8.2. Определение и вызов функции
- •8.3. Место определения функции в программе
- •8.4. Обмен данными между функциями
- •8.4.1. Использование глобальных переменных
- •8.4.2. Использование аппарата формальных и фактических параметров
- •8.4.3. Передача массивов в функцию
- •8.5. Перегрузка функции
- •8.6. Шаблон функции
- •8.7. Рекурсивные функции
- •8.8. Функции с параметрами по умолчанию
- •8.9. Передача в функцию другой функции
- •9. Работа с файлами
- •9.1. Текстовые и двоичные файлы
- •9.2. Объявление файловых переменных
- •9.3. Чтение текстового файла
- •9.4. Создание текстового файла
- •9.5. Изменение данных в текстовом файле
- •9.6. Вывод в двоичный файл
- •9.7. Чтение данных из двоичного файла
- •9.8. Изменение данных двоичного файла
- •9.9. Организация файла с произвольным доступом
- •10. Данные с динамической структурой
- •10.1. Линейный список
- •10.1.1. Специальные типы линейных списков
- •10.1.2. Реализация линейного списка с помощью массива
- •10.1.3. Реализация линейного списка с помощью связанного однонаправленного списка
- •10.1.4. Реализация линейного списка с помощью связанного двунаправленного списка
- •10.2. Деревья
- •10.2.1. Основная терминология
- •10.2.2. Реализация двоичных деревьев поиска Для реализации дерева поиска используются массивы и связанные указателями элементы [3, 4].
- •10.2.3. Сбалансированные деревья
- •Основные достоинства в-дерева:
- •10.3. Графы
- •10.3.1. Определения
- •10.3.2. Реализация графа с помощью списков смежности
- •10.3.3. Реализация графа с помощью матрицы смежности
- •10.3.4. Поиск кратчайших путей. Алгоритм Дейкстры
- •10.3.5. Матрица достижимости. Алгоритм Уоршалла
10.3.4. Поиск кратчайших путей. Алгоритм Дейкстры
Постановка задачи
Дан взвешенный граф без петель и дуг с отрицательным весом. Найти кратчайшие пути от некоторой вершины с номером k до всех остальных вершин этого графа.
Каждой вершине из массива вершин V сопоставим метку – минимальное известное расстояние от источника (вершины с номером k) до этой вершины. Алгоритм работает пошагово – на каждом шаге алгоритм посещает одну вершину и пытается уменьшить метки. Работа алгоритма завершается, когда все вершины посещены.
Рассмотрим выполнение алгоритма на примере графа, показанного на рис. 5. Пусть требуется найти расстояния от вершины 1 до всех остальных. Все вершины графа помечаются как необработанные: кратчайшие расстояния от вершины 1 до других вершин полагаются равными бесконечности. Расстояние от вершины 1 до самой себя полагается равной 0. На рис. 82 показано начальное состояние графа.
Рис. 8. Начальное состояние графа
На каждом шаге алгоритма используется массив D, в который записываются минимальные известные расстояния от источника до каждой вершины графа. В алгоритме используется также массив S, в котором на каждом шаге отмечаются обработанные вершины. Начальные состояния массивов для графа, изображенного на рис. 8:
Массив D: 0, ∞, ∞, ∞, ∞, ∞
Массив S: false, false, false, false, false, false
В алгоритме используется матрица стоимости, элемент которой c[i][j] равен стоимости дуги: если дуги из вершины i в вершину j не существует, то c[i][j]= ∞, если существует, то c[i][j]=a[i][j]. Здесь a[i][j] элемент матрицы смежности.
На каждом шаге алгоритма посещается вершина, которая не обработана (она отмечена в массиве S как false) и расстояние до которой от источника минимально (на основе данных массива D). Эта вершина помечается в массиве S как обработанная. Далее алгоритм пытается уменьшить метки смежных с выбранной вершиной вершин в массиве D, оценивая для каждой смежной вершины путь от источника через текущую вершину. Если длина нового пути через текущую вершину меньше расстояния, зафиксированного для смежной вершины в массиве D, то соответсвующее значение в массиве D изменяется. Алгоритм заканчивается, когда все вершины помечены как обработанные. В табл. 8 приведены последовательности значений массивов D и S после каждой итерации цикла алгоритма Дейкстры для графа, изображенного на рис. 5.
Таблица 8
Последовательности значений массивов D и S
Итерация |
S |
D[1] |
D[2] |
D[3] |
D[4] |
D[5] |
D[6] |
1 |
tfffff |
0 |
7 |
9 |
|
|
14 |
2 |
ttffff |
0 |
7 |
9 |
22 |
|
14 |
3 |
tttfff |
0 |
7 |
9 |
20 |
|
11 |
4 |
tttfft |
0 |
7 |
9 |
20 |
20 |
11 |
5 |
ttttft |
0 |
7 |
9 |
20 |
20 |
11 |
6 |
tttttt |
0 |
7 |
9 |
20 |
20 |
11 |
Текст фукции, реализующей алгоритм Дейкстры:
void Dijkstra(int d[ ], int a[][size], int n, int k)
/* d - массив кратчайших путей от к-вершины до каждой вершины, a - матрица смежности, n - количество вершин графа,
k - вершина-источник, size - глобальная константа */
{
int c[size][size]; //матрица стоимости
bool s[size]; //массив обработанных вершин
int dmin, imin; //минимальное расстояние от источника до
//необработанной вершины и номер этой вершины
int i, j; //номера вершин
int m; //количество обработанных вершин
//Заполнение матрицы стоимости
for (i=0; i<=n-1; i++)
for (j=0; j<=n-1; j++)
if (a[i][j]==0 && i!=j)
c[i][j]=1000;
else
c[i][j]=a[i][j];
//Начальное заполнение массива обработанных вершин
for (i=0; i<=n-1; i++)
s[i]=false; //все вершины не посещались
m=0; //нет обработанных вершин
//Начальное заполнение массива известных кратчайших путей
// от k-вершины до других вершин
for (i=1; i<=n-1; i++)
d[i]=100000; //100000 равносильно бесконечному расстоянию
d[k]=0; //источник имеет минимальную метку, с него начинать
//Главный цикл
dmin=0; //чтобы войти в цикл
while (m!=n && dmin!=100000) //цикл закончится когда все
//вершины обработаны (m==n) или нет
// путей к необработанным вершинам
{ //поиск необработанной вершины, расстояние до которой
//минимально
dmin=1000;
for(i=0; i<=n-1; i++)
if(d[i]<dmin && s[i]==false)
{dmin=d[i]; imin=i; }
if(dmin!=100000) //есть пути к необработанным вершинам
{
s[imin]=true; //добавление найденной вершины в s
m++;
//Вычисление кратчайших расстояний от источника
//(вершины k) до смежных с imin вершин
for (j=0; j<=n-1; j++)
if(a[imin][j]!=0&& s[j]==false) //j-смежная и не обработана
if(c[imin][j]+d[imin]<d[j]) //расстояние от источника до j-//вершины через imin-вершину
d[j]=c[imin][j]+d[imin];//замена метки вершины в массиве d
}
}
}