Перейти к содержанию

11.2 Представление графов

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

Рассмотрим три наиболее распространённых способа:


1. Представление списками смежности

В этом способе для каждой вершины хранится список вершин, в которые из неё есть рёбра.

Это самый популярный способ представления графа.

Идея

Для каждой вершины x мы храним список всех вершин, достижимых из x.

Пример графа

flowchart LR
    1 --> 2
    2 --> 3
    2 --> 4
    3 --> 4
    4 --> 1
Hold "Ctrl" to enable pan & zoom

Хранение

vector<int> adj[N];

Заполнение (пример)

adj[1].push_back(2);
adj[2].push_back(3);
adj[2].push_back(4);
adj[3].push_back(4);
adj[4].push_back(1);

Неориентированный граф

Если граф неориентированный, каждое ребро добавляется в обе стороны:

adj[a].push_back(b);
adj[b].push_back(a);

Взвешенный граф

Если у рёбер есть веса:

vector<pair<int,int>> adj[N];

Теперь в списке хранится (вершина, вес).

Пример

flowchart LR
    1 -- 5 --> 2
    2 -- 7 --> 3
    2 -- 6 --> 4
    3 -- 4 --> 4
    4 -- 2 --> 1
Hold "Ctrl" to enable pan & zoom
adj[1].push_back({2,5});
adj[2].push_back({3,7});
adj[2].push_back({4,6});
adj[3].push_back({4,4});
adj[4].push_back({1,2});

Перебор соседей

for (auto u : adj[s]) {
    // обработка вершины u
}

Плюсы

  • быстро перебираются соседи вершины
  • экономит память
  • подходит для больших графов

2. Представление матрицей смежности

Здесь используется двумерный массив n × n.

Идея

adj[a][b] = 1, если есть ребро из a в b, иначе 0.


Пример

flowchart LR
    1 --> 2
    3 --> 4
    2 --> 4
Hold "Ctrl" to enable pan & zoom

Матрица

    1 2 3 4
1 [ 0 1 0 0 ]
2 [ 0 0 0 1 ]
3 [ 0 0 0 1 ]
4 [ 0 0 0 0 ]

Хранение

int adj[N][N];

Взвешенный граф

Вместо 0/1 храним вес:

adj[a][b] = вес ребра
adj[a][b] = INF, если ребра нет

Плюсы

  • можно за O(1) проверить наличие ребра

Минусы

  • требует O(n²) памяти
  • не подходит для больших разреженных графов

3. Представление списком рёбер

В этом способе хранится просто список всех рёбер.

Хранение

vector<pair<int,int>> edges;

Каждая пара (a, b) означает ребро из a в b.


Пример

flowchart LR
    1 --> 2
    2 --> 3
    3 --> 4
Hold "Ctrl" to enable pan & zoom
edges.push_back({1,2});
edges.push_back({2,3});
edges.push_back({3,4});

Когда использовать

Этот способ удобен, если:

  • нужно обработать все рёбра
  • не требуется быстро находить соседей вершины

Сравнение

Способ Память Быстрый доступ к соседям Проверка ребра
Списки смежности O(n + m) ✅ быстро ❌ медленно
Матрица смежности O(n²) ❌ медленно ✅ быстро
Список рёбер O(m) ❌ нет ❌ нет

Вывод

  • Списки смежности — основной выбор в большинстве задач
  • Матрица — когда нужен быстрый доступ к рёбрам
  • Список рёбер — когда работаем с рёбрами напрямую