<<
>>

Выбор кратчайшего пути

Начнем наше изучение алгоритмов выбора маршрутов с метода, широко применяемого в различных формах благодаря его простоте и понятности. Идея заключается в построении графа подсети, в котором каждый узел будет соответствовать маршрутизатору, а каждая дуга — линии связи (часто называемой просто связью).
При выборе маршрута между двумя маршрутизаторами алгоритм просто находит кратчайший путь между ними на графе.

Концепция кратчайшего пути требует некоторого пояснения. Один из способе измерения длины пути состоит в подсчете количества транзитных участков. В таком случае пути АВС и ABE на рис. 5.6 имеют одинаковую длину. Можно измерять расстояния в километрах. В таком случае окажется, что путь АВС значительно длиннее пути ABE (предполагается, что рисунок изображен с соблюдением масштаба).

Рис. 5.6. Первые пять шагов вычисления кратчайшего пути от Л к О.

Стрелка указывает на рабочий узел

Однако помимо учета количества транзитных участков и физической длины линий возможен учет и других параметров. Например, каждой дуге графа можно поставить в соответствие среднюю длину очереди и время задержки пересылки, определяемые каждый час с помощью передачи специального тестового пакета. В таком графе кратчайший путь определяется как самый быстрый путь, а не путь с самой короткой длиной кабеля или путь, состоящий из минимального числа отдельных отрезков кабеля.

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

Известно несколько алгоритмов вычисления кратчайшего пути между двумя узлами графа. Один из них был создан знаменитым Дейкстрой (Бцкйга) в 1959 году. Каждый узел помечается (в скобках) расстоянием до него от узла отправителя по наилучшему известному пути. Вначале пути неизвестны, поэтому все узлы помечаются символом бесконечности. По мере работы алгоритма и нахождения путей отметки узлов изменяются, показывая оптимальные пути. Отметка может быть постоянной или экспериментальной. Вначале все отметки являются ориентировочными. Когда выясняется, что отметка действительно соответствует кратчайшему возможному пути, она становится постоянной и в дальнейшем не изменяется.

Чтобы показать, как работает этот алгоритм, рассмотрим взвешенный ненаправленный граф (рис. 5.6, а), где весовые коэффициенты соответствуют, например, расстояниям. Мы хотим найти кратчайший путь от А к D. Для начала мы черным кружком помечаем узел А как постоянный. Затем мы исследуем все соседние с ним узлы, указывая около них расстояние до узла А. Если отыскивается более короткий путь к какому-либо узлу, то вместе с указанием расстояния в отметке меняется и узел, через который прошел более короткий путь. Таким образом, позднее можно восстановить весь путь. Рассмотрев все соседние с А узлы, мы помечаем ближайший узел как постоянный, как показано на рис. 5.6, б. Этот узел становится новым рабочим узлом.

Теперь мы повторяем ту же процедуру с узлом В, исследуя все его соседние узлы. Если сумма расстояния от узла В и значения отметки в узле В (расстояния от А до В) оказывается меньше, чем отметка у исследуемого узла (уже найденное другим путем расстояние от Л), это значит, что найден более короткий путь, поэтому пометка узла изменяется.

После того как все соседние с рабочим узлы исследованы и временные отметки при необходимости изменены, по всему графу ищется узел с наименьшей временной отметкой. Этот узел помечается как постоянный и становится текущим рабочим узлом. На рис. 5.6 показаны первые пять этапов работы алгоритма.

Чтобы понять, как работает алгоритм, посмотрим на рис. 5.6, в. На данном этапе узел Е только что был отмечен как постоянный. Предположим, что существует более короткий путь, нежели ABE, например AXYZE. В этом случае есть две возможности — либо узел Z уже сделан постоянным, либо еще нет. Если да, значит, узел Е уже проверялся, когда узел Z был сделан постоянным и, следовательно, рабочим узлом. В этом случае путь AXYZE уже исследовался.

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

Этот алгоритм приведен в листинге 5.1. Глобальные переменные п и dist описывают граф и инициализируются раньше, чем вызывается shortest_path. Единственное отличие программы от описанного выше алгоритма заключается в том, что вычисление кратчайшего пути в программе начинается не от узла-источника s, а от конечного узла t. Поскольку в однонаправленном графе кратчайший путь от t к s тот же самый, что и от s к t, не имеет значения, с какого конца начинать. (Если только не существует несколько кратчайших путей. В таком случае, двигаясь в противоположном направлении, мы можем обнаружить другой путь.) Причина поиска пути в обратном направлении заключается в том, что каждый узел помечается предшествующим узлом, а не следующим. Когда найденный путь копируется в выходную переменную path, он инвертируется. С помощью реверсивного поиска убирается неправильность направления поиска, и мы получаем путь, идущий в нужную сторону.

Листинг 5.1. Алгоритм Дейкстры вычисления кратчайшего пути по графу

#define MAX_N0DES 1024 /* максимальное количество узлов */

idefine INFINITY 1000000000 /* число, большее длины максимального пути */

int n, dist[MAX_NODES][MAX_N0DES]: /* dist[i][j] - это расстояние от i до j */ void shortest_path(int s, int t, int path[])

{ struct state { /* рабочий путь */

int predecessor: /* предыдущий узел */

int length: /* расстояние от источника до этого узла */

enum {permanent, tentative} label: /* метка состояния */

} state[MAX_N0DES]: int i.

k, min; struct state *p;

for (p = &state[0]: p < &state[n]; p++) { /* инициализировать состояние */ p->predecessor = -1; p->length = INFINITY; p->label - tentative:

}

state[t],length = 0; state[t],label = permanent:

k - t: /* k - начальный рабочий узел */

do { /* Есть ли лучший путь от к? */

for (i - 0: i < n; i++) /* У этого графа п узлов */

if (dist[k][1 ] !- 0 && stated],label -- tentative) { if CstateCk].length + dist[k][i] < stated],length) { stated],predecessor - k: stated].length - state[k],length + dist[k][1 ];

}

}

/* Найти узел, помеченный как предварительный с наименьшей меткой */ к - 0; min - INFINITY: for (i - 0; i < n: i++)

if (stated],label ■■ tentative && stated],length < min) { m1n - stated],length; к -i;

}

state[k],label - permanent;

} while (k !- s);

/* Копировать путь в выходной массив */

1 - 0: к - s:

do (path[i++] - к; к - stateCk].predecessor; } while (к >- 0);

<< | >>
Источник: Э. ТАНЕНБАУМ. КОМПЬЮТЕРНЫЕ СЕТИ 4-Е ИЗДАНИЕ. 2003

Еще по теме Выбор кратчайшего пути:

  1. Выбор линейного мышления - это выбор прожить жизнь в танце частиц.
  2. Выбор есть. Он существует всегда. Сознание - это выбор.
  3. Пути оттока
  4. Будьте верны своему пути
  5. Первая глава НА ПУТИ К ЧЕТВЕРТОМУ ИЗМЕРЕНИЮ
  6. Защита в пути
  7. По пути самосовершенствования
  8. По пути самосовершенствования
  9. НА ПУТИ К ЗРЕЛОМУ СОЕДИНЕНИЮ
  10. Четыре пути к самоуважению
  11. ЛОВУШКИ НА ПУТИ ПЕРЕМЕН
  12. Часть первая. Первые шаги на пути к успеху