Pull to refresh

Эффективное хранение графов: матрицы смежности

Reading time3 min
Views6.4K

Как известно, представление графа в памяти преимущественно осуществляется двумя способами: матрицей смежности и списком смежности. Остановимся на первом из них.

Матрица смежности графа

Стоит отметить, что размер, выделяемый для хранения обыкновенной матрицы смежности, равняется n^2 где n- количество вершин в графе.

Рассмотрим ориентированный граф, состоящий из четырех вершин:

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

Матрица смежности для такого графа будет иметь вид: (INF означает отсутствие ребра)

INF

7

INF

5

INF

INF

INF

9

INF

INF

INF

INF

INF

INF

2

INF

Битовая матрица смежности

Предположим, что нас не интересуют веса ребер графа, то есть будем говорить лишь о наличии ребра из одной вершины в другую. В таком случае размер, выделяемый под матрицу смежности ориентированного графа, можно уменьшить в 8 раз, соответственно до: (n^2/8) + 1. Назовем такую матрицу смежности битовой матрицей смежности для графа. Изначально она инициализирована нулями.

  1. Рассмотрим функцию добавления значения в битовую матрицу смежности:

index = (line * numberOfVertices + column) / 8;
binaryMask = 128 >> ((line * numberOfVertices + column) % 8);
matrix[index] |= binaryMask;

Число 128 выбрано не просто так: его двоичное запись = 100000002. Здесь binaryMask представляет собой двоичную маску наличия ребра для текущей пары вершин line и column, формируемую побитовым сдвигом вправо. Дальнейшее выполнение "побитового или" позволяет добавить эту информацию в матрицу.

  1. Рассмотрим функцию получения значения из битовой матрицы смежности:

index = (line * numberOfVertices + column) / 8;
binaryMask = 128 >> ((line * numberOfVertices + column) % 8);
binaryMask &= matrix[index];

Отличий от функции добавления значения в матрицу немного: вместо того, чтобы совершать операцию "побитого или" для матрицы, мы совершаем операцию "побитового и" для двоичной маски, которая даёт возможность узнать информацию о наличии ребра между вершинами line и column: если binaryMask == 0, то ребра нет, иначе - ребро есть.

Замечу, что в функциях, описанных выше, я полагал по определению, что line и column - это вершины графа, номера которых >= 1.

Пример работы с битовой матрицей смежности:

Пусть дан следующий ориентированный граф:

Произвольный ориентированный граф
Произвольный ориентированный граф

Размер, выделяемый для хранения битовой матрицы смежности будет равняться: size = (4^2 /8)+1 = 3

А значит такая матрица имеет вид: (индексация ячеек матрицы с нуля)

0

0

0

Добавим ребро 1-2:
index = (1 * 4 + 2) / 8 = 0
binaryMask = 128 >> 6 = 2 = 000000102

0 0 0 0 0 0 1 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

Добавим ребро 1-4:
index = (1 * 4 + 4) / 8 = 1
binaryMask = 128 >> 0 = 128 = 100000002

0 0 0 0 0 0 1 0

1 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

Добавим ребро 2-4:
index = (2 * 4 + 4) / 8 = 1
binaryMask = 128 >> 4 = 8 = 000010002

0 0 0 0 0 0 1 0

1 0 0 0 1 0 0 0

0 0 0 0 0 0 0 0

Наконец, добавим ребро 4-3:
index = (4 * 4 + 3) / 8 = 2
binaryMask = 128 >> 3 = 16 = 000100002

0 0 0 0 0 0 1 0

1 0 0 0 1 0 0 0

0 0 0 1 0 0 0 0

Теперь, используя полученную матрицу смежности, попробуем ответить на следующий вопрос: есть ли в этом графе ребро между вершинами 1-4?
index(1;4) = (1*4+4)/8=1
binaryMask(1;4) = 128 >> 0 = 128

10001000 & 10000000 = 1 => ребро есть.

А между вершинами 1-3?
index(1;3) = (1*4+3)/8=0
binaryMask(1;3) = 128 >> 7 = 1

00000010 & 00000001 = 0 => ребра нет.


Хранение половины (треугольной) матрицы смежности

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

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

INF

4

8

4

INF

17

8

17

INF

Размер, выделяемый под треугольную матрицу смежности неориентированного графа, будет равняться: n * (n+1)/2, если нам нужно хранить её главную диагональ.

Треугольная матрицы смежности такого графа примет вид:

INF

4

INF

8

17

INF

  1. Рассмотрим функцию получения индекса для этой матрицы:

maxVertex = max(line, column);
minVertex = min(line, column);
index = (maxVertex * (maxVertex - 1) / 2) + minVertex - 1;
  1. Добавление и получение значений из треугольной матрицы смежности аналогично обычной матрице смежности, но по индексу, полученному выше.

Замечу, что здесь я так же предполагал line и column вершинами графа, номера которых >= 1.

Итоги

Эту статью я написал, потому что в своё время сам нуждался в данной информации. Благодарю всех читателей и надеюсь, что помог кому-нибудь.


Визуализацию графов проводил с помощью сайта: graphonline.ru.

Tags:
Hubs:
Total votes 4: ↑3 and ↓1+2
Comments7

Articles