Представление графов в памяти
компьютера
(с примерами на C++)
Максименкова Ольга Вениаминовна
Старший преподаватель Департамента программной инженерии
Факультета компьютерных наук
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 1
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 2
const int N = 3;
const int M = 5;
const int K = 7;
int main() {
int multiArr[N][M][K] = { 1, 2, 3, 4, 5, 6, 7, 8 };
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
for (int k = 0; k < K; k++)
cout << multiArr[i][j][k] << " ";
return 0;
}
int arr[10]; // определён массив из 10 элементов
for (int i = 0;i < 10;i++)
cout << arr[i] << " ";
return 0;
-858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460
1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Здесь есть инициализация!
А здесь нет!
Если заменить arr[i] на (arr+i),
можно убедится, что адреса разные.
Но *(arr+i) даст такой же вывод.
Цели лекции
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 3
Рассмотреть
• Варианты представления графов в памяти компьютера
• Некоторые способы реализации этих представлений на
языке C++
Выявить
• Способы повышения быстродействия и экономии памяти
для частных случаев
Соглашения о терминологии
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 4
Мультиграф [multigraph] – граф, содержащий кратные рёбра.
Незнанов А.А., Кохов В.А. Алгоритмизация решения переборных задач анализа графов – М.: Издательский дом МЭИ,
2007. – 80 с.
Граф – неориентированный граф без петель и кратных рёбер.
Обозначение графа: G = (V, E), где идентификаторами (номерами) вершин и
ребер выступают числа натурального ряда:
 V = {v1, v2, … , vp} = {0, 1, … , p1}, p = |V| – число вершин;
 E = {e1, e2, … , eq} = {0, 1, … , q1}, q = |E| – число ребер.
Петля [loop] – ребро, инцидентное только одной вершине (соединяет вершину с
самой собой).
Кратными (или мультирёбрами) [multiple] называются рёбра, инцидентные
одной и той же паре вершин.
Две вершины смежны [adjacent], если они соединены ребром.
Два ребра смежны [adjacent], если они имеют общую вершину.
Базовые представления
Индексные представления графа/орграфа в памяти компьютера
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 5
Матрица смежности
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ
6
Матрица смежности графа – квадратная матрица A с числом строк и столбцов,
равным p. Элемент Ai j = 1, если существует дуга (i, j), в противном случае Ai j = 0. Для
мультиграфов вместо 1 заносится кратность мультиребра.
Объём памяти p2·a, где a – размер
элемента матрицы
int mtr[n][n] = {
{0,1,0,0,1},
{1,0,1,1,1},
{0,1,0,1,0},
{0,1,1,0,1},
{1,1,0,1,0}
};
cout << n*n*sizeof(int);
0 1 0 0 1
1 0 1 1 1
0 1 0 1 0
0 1 1 0 1
1 1 0 1 0
1
2
3
4
5
1 2 3 4 5
Для графов с весами на дугах, вместо 1 заносится вес ребра. Как перепишется
матрица смежности для примера выше?
5
1
2
34
1
7
2
3
4
5
6
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 7
5 2
34
4
7
12
3
5
6
9
8
0 1 0 0 1
1 0 2 0 1
0 2 0 2 0
0 0 2 0 2
1 1 0 2 0
1
2
3
4
5
1 2 3 4 5
Мультиграф
int mtr[n][n] = {
{0,1,0,0,1},
{1,0,2,0,1},
{0,2,0,2,0},
{0,0,2,0,2},
{1,1,0,2,0}
};
cout << n*n*sizeof(int);
Для всех видов графов веса вершин задают на главной диагонали
матрицы A или в виде дополнительного массива WV.
На чём можно сэкономить?
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 8
Для обыкновенного графа допустимо хранение только части матрицы смежности
– над главной диагональю.
int main() {
int** mtrSeg = new int*[n];
for (int i = 0; i < n; i++)
*(mtrSeg + i) = new int[n - i];
mtrSeg[0][0] = mtrSeg[0][3] = 1;
mtrSeg[0][1] = mtrSeg[0][2] = 0;
mtrSeg[1][0] = mtrSeg[1][1] = mtrSeg[1][2] = 1;
mtrSeg[2][0] = 1; mtrSeg[2][1] = 0;
mtrSeg[3][0] = 1;
for (int i = 0; i < n; i++) { // вывод
cout << "n";
for (int j = 0; j < n - i - 1; j++)
cout << *(*(mtrSeg + i)+j);
}
0 1 0 0 1
1 0 1 1 1
0 1 0 1 0
0 1 1 0 1
1 1 0 1 0
1
2
3
4
5
1 2 3 4 5
На чём можно сэкономить?
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 9
При отсутствии весов можно использовать битовую матрицу (каждый элемент
занимает один бит).
Brendan McKay and Adolfo Piperno. nauty and Traces (http://pallini.di.uniroma1.it)
Посмотреть вариант реализации подробно…
cout << "Memory size: " << sizeof(AdjMatr) + sizeof(rowSize*p);
Memory size: 8
FO и FI-представления
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 10
Для неориентированных графов определено только FO-представление,
реализуемое одним одномерным массивом.
5 2 5 0 13 4 5 0 4 2 0 3 2 50 1 2 4 0
Количество
вершин графа
(p)
Номера вершин,
смежных с
первой
Номера вершин,
смежных со
второй
Разделитель
(ноль)
Если нумерация вершин начинается с нуля, роль разделителя играет другой символ,
например -1.
Длина массива FO: 1 + 2·q + p, где q – количество рёбер, а p – количество
вершин графа.
5
1
2
34
1
7
2
3
4
5
6
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 11
#include <iostream>
using namespace std;
// число вершин
const int p = 5;
// число рёбер
const int q = 7;
int main() {
int FO[1 + 2 * q + p] = { 5,2,5,0,
1,3,4,5,0,
4,2,0,
3,2,5,0,
1,2,4,0 };
cout << "nNode: " << 1 << "nt";
for (int i = 0, j = 1; i < 1 + 2 * q + p;i++) {
if (FO[i] == 0) {
j++;
cout << "nNode: "<< j << "nt";
continue;
}
else cout << FO[i] << " ";
}
return 0;
}
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 12
Варианты для орграфа:
1. для каждой вершины записываются номера вершин, в которые из этой вершины
исходят дуги (FO-представление),
2. Для каждой вершины записываются номера вершин, из которых исходят дуги в эту
вершину (FI-представление).
Длина массивов FO и FI равна 1 + q + p.
5
1
2
34
1
7
2
3
4
5
6
Задание на 5 минут: Напишите FO и FI
представления для этого орграфа. В качестве
разделителя используйте ноль.
Ответ:
FO 5 2 5 0 3 4 5 0 4 0 0 4 0
FI 5 0 1 0 2 0 2 5 3 0 1 2 0
На практических занятиях реализуйте данное представление на языке C++. Для
каждой вершины вычислите абсолютную разность сумм весов входящих и выходящих
рёбер. Результат вывести на экран.
MFO и MFI-представления
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 13
Для неориентированных графов определено только MFO-представление.
5
1
2
34
1
7
2
3
4
5
6
Номера вершин,
смежных с
первой
Номера вершин,
смежных со
второй
Длина массива ME равна 2 · q.
Длина массива MV равна p + 1
MFO =
ME 2 5 1 3 4 5 4 2 3 2 5 1 2 4
MV 0 2 6 8 11 14 P 5
Индекс последнего
элемента ME плюс 1
Индекс первого
элемента ME, смежного
с первой вершиной
Индекс первого
элемента ME, смежного
со второй вершиной
Пример реализации
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 14
#include <iostream>
using namespace std;
// число вершин
const int p = 5;
// число рёбер
const int q = 7;
int main() {
int ME[2 * q] = {2,5,1,3,4,5,4,2,3,2,5,1,2,4};
int MV[p + 1] = { 0,2,6,8,11,14 };
// цикл по вершинам
for (int i = 0; i < p; i++) {
cout << "Node " << i << ":nt";
// перебор вершин, смежных с данной (соседей)
for (int j = MV[i]; j < MV[i + 1];j++)
cout << ME[j] << " ";
cout << "n";
}
return 0;
}
5
1
2
34
1
7
2
3
4
5
6
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 15
Длина массива ME равна q.
Длина массива MV равна p + 1
5
1
2
34
1
7
2
3
4
5
6
Варианты для орграфа:
1. FO-представление записывается в виде двух массивов (выходящие рёбра)
2. FI-представление записывается в виде двух массивов (входящие рёбра)
Задание на 5 минут: Напишите MFO представление для этого орграфа.
Ответ:
MFI =
ME 1 2 2 3 5 1 2
MV 0 0 1 2 3 5 7 P 5
MFO =
ME 2 5 3 4 5 4 4
MV 0 2 5 6 6 7 P 5
На практических занятиях реализуйте данное представление на языке C++.
На чём можно сэкономить?
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 16
В массивы FO и ME для каждой вершины записываются только те номера вершин,
которые не меньше (или не больше) номера этой вершины.
Это позволяет уменьшить размер массива FO c (1+2q+p) до (1+q+p), а массива
ME – с 2q до q.
Для неориентированных графов допустимы сокращённые FO- и MFO-
представления (BFO и BMFO)
BFO 5 2 5 0 34 5 0 4 0 5 0 0
5
1
2
34
1
7
2
3
4
5
6
FO 5 2 5 0 13 4 5 0 4 2 0 3 2 50 1 2 4 0
Сравните:
Матрица инциденций
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 17
Матрица инциденций графа – прямоугольная матрица В с числом строк p и
числом столбцов q. Каждый столбец соответствует одному из рёбер. Столбец,
соответствующий ребру e = {i, j} содержит 1 в i-й и j-й строке, в остальных строках
содержатся нули. Столбец, соответствующий петле, содержит единственную 1.
Для орграфа начало и конец дуги задаются разными числами (например, –1 –
начало, 1 – конец).
Для мультиграфа можно либо рассматривать каждое ребро в составе мультиребра
как отдельное (с записью в отдельный столбец), либо записывать значение
кратности ребра вместо 1.
Представление занимает объём памяти, равный pqa, где a – размер
элемента матрицы.
5
1
2
34
1
7
2
3
4
5
6
1 1 0 0 0 0 0
0 1 1 1 1 0 0
0 0 0 1 0 1 0
0 0 0 0 1 1 1
1 0 1 0 0 0 1
1
2
3
4
5
1 2 3 4 5 6 7
Примеры матриц инциденций
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 18
5
1
2
34
1
7
2
3
4
5
6
1 1 0 0 0 0 0
0 -1 1 1 0 1 0
0 0 0 -1 1 0 0
0 0 0 0 -1 -1 -1
-1 0 -1 0 0 0 1
1
2
3
4
5
1 2 3 4 5 6 7
5
1
2
34
4
7
12
3
5
6
9
8
1 1 0 0 0 0 0 0 0
1 0 1 1 1 0 0 0 0
0 0 0 1 1 1 1 0 0
0 0 0 0 0 1 1 1 1
0 1 1 0 0 0 0 1 1
1
2
3
4
5
1 2 3 4 5 6 7 8 9
Мультиграф
Орграф
Массив рёбер
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 19
Массив рёбер графа – прямоугольная матрица C с двумя строками и числом
столбцов q.
Каждый столбец соответствует одному из рёбер.
В столбце, соответствующем ребру e = {i, j} первый элемент содержит i, а второй
– j.
5
1
2
34
1
7
2
3
4
5
6
1 2 2 2 3 4 5
2 3 4 5 4 5 1
q = 7
1 1 2 2 2 3 4
2 5 3 4 5 4 5
Отсортированный
C =
void setRib(rib& r, int a, int b) {
r.beg = a;
r.end = b;
}
struct rib {
int beg;
int end;
};
rib C[q];
Ссылочные
представления
Списки смежности
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 20
Списки смежности
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 21
2
Указатель на граф
4 NULL
1 3
NULL
NULL
2 4 NULL
4
1 2 NULL3
1
24
12
3
4
5
3
Список LV содержит ссылки на
списки смежности отдельных
вершин LEi.
Каждый список смежности LEi– список
(обычно односвязный) номеров вершин,
смежных c вершиной i.
Организация списков смежности
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 22
// элемент списка смежности
struct AdjList {
AdjList* next; // следующий элемент списка
int w; // номер вершины
};
// вершина графа
struct VerList {
AdjList* head; // указатель на начало списка смежности
VerList* next; // следущая вершина
};
Односвязные списки, построенные при помощи структур
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 23
int main() {
VerList LVtmp;
VerList* LVhead=&LVtmp; // указатель на начало списка
// первая смежная с первой вершина
AdjList ELtmp1;
ELtmp1.next = NULL;
ELtmp1.w = 2;
// вторая смежная с первой вершина
AdjList newEL;
newEL.next = NULL;
newEL.w = 4;
// добавили вторую в список
ELtmp1.next = &newEL;
// связываем список смежности с первой вершиной
LVtmp.head = &ELtmp1;
LVtmp.next = NULL;
cout << LVtmp.head->w << " ";
cout << LVtmp.head->next->w;
return 0;
}
Очень подробный пример очень нереального кода
2 4 NULL
Требуется декомпозиция!
Объектно-
ориентированные
представления
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 24
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 25
Объект-вершина
Объект-ребро
Edges
Веса
Edges
Веса
Edges
Веса
Edges
Веса
1
2
3
4
SourceV1
DestV
SourceV5
DestV
SourceV4
DestV
SourceV3
DestV
SourceV2
DestV
Веса
Веса
Веса
Веса
Веса
1
24
12
3
4
5
3
Объектно-ориентированная библиотека
для работы с графами
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 26
Boost Graph Library (BGL). Graph interface
(http://www.boost.org/doc/libs/1_58_0/libs/graph/doc/graph_concepts.html)
Рекомендации по применению
представлений
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 27
Применение матрицы смежности является оправданным, когда:
1) число вершин невелико (p  1000), а число рёбер велико (стандартная
оценка для обыкновенного графа: > p(p1)/4);
2) когда необходимо иметь быстрый доступ к произвольным рёбрам графа;
3) когда часто необходимо добавлять и удалять рёбра при неизменном числе
вершин.
Когда трансформация графа не требуется, хорошим компромиссом для графов
общего вида является MFO-представление и его варианты (списки смежности
и др.).
Матрица инциденций – самое невыгодное с алгоритмической
точки зрения представление графа.
Сложность базовых операций при
различных представлениях графа
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 28
№ Представление
Асимптотическая сложность
операций
IsEdge AddEdge ForAllAdj
1 Матрица смежности 1 1 p
2 Матрица инциденций q p+alloc pq
3 Массив рёбер q alloc q
4 Отсортированный массив рёбер log(q) q+alloc
log(q)+de
g(i)
5 FO-представление p+q p+q+alloc p+q
6 MFO-представление
max(deg(i),
deg(j))
q+alloc deg(i)
7 Отсортированное MFO-представление
max(log(deg(i
)), log(deg(j)))
q+alloc deg(i)
Приложения
Завершить показ
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 29
Вариант реализации матрицы смежности
через битовую матрицу
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 30
#include <iostream>
using namespace std;
// число вершин графа
const unsigned int p = 5;
// размер unsigned int в битах
const unsigned int ElSize = sizeof(unsigned int) << 3;
// Двоичный логарифм от размера unsigned int в битах
const unsigned int LogElSize = log2(sizeof(unsigned int)) + 3;
// длина строки битовой матрицы в unsigned int
const unsigned int rowSize = (p + (sizeof(unsigned int) << 3) - 1)
>> LogElSize;
// массив указателей на строки матрицы смежности
unsigned int* AdjMatRows[p];
// указатель на саму битовую матрицу
unsigned int* AdjMatr;
5
1
2
34
Выделение памяти под битовую
матрицу
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 31
int main() {
// выделяем память под матрицу смежности
AdjMatr = new unsigned int[rowSize*p];
// зануляем элементы
for (int i = 0; i < rowSize*p; AdjMatr[i] = 0,i++);
// связываем указатели на строки матрицы с участками памяти
*AdjMatRows = AdjMatr;
for (int i = 1; i < p; i++)
AdjMatRows[i] = AdjMatRows[i - 1]+ rowSize;
// здесь добавляем рёбра, вычисления, что угодно...
delete AdjMatr;
delete AdjMatRows;
return 0;
}
Добавления ребра… Куда поставить 1?
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 32
// функция добавления ребра между вершинами a и b
void addEdge(int a, int b) { // номера вершин
// находим нужный uint в строке a
unsigned int w = AdjMatRows[a][b >> LogElSize];
// проверяем бит с номером остаток от деления b на число
бит в unsigned int
unsigned int e = 1 << (b & (ElSize - 1));
if (!(w & e)) {
// добавляем A[a,b]
AdjMatRows[a][b >> LogElSize] = w | e;
// добавляем A[b,a]
w = AdjMatRows[b][a >> LogElSize];
e = 1 << (a & (ElSize - 1));
AdjMatRows[b][a >> LogElSize] = w | e;
}
}
Функция печати битовой матрицы
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 33
// функция печати матрицы смежности
void printMat() {
for (int i = 0; i < p; i++) { // вывод
cout << "n";
for (int j = 0; j < rowSize; j++)
// битовое представление строки
for (int k = 0; k < p; k++)
cout << ((AdjMatRows[i][j] >> k) & 1);
}
cout << "n";
}
На практических занятиях:
1) запустите код и протестируйте его для матриц смежности графов с 32 и более
вершинами.
2) допишите функцию удаления ребра между вершинами a и b.
Окончание функции main()
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 34
addEdge(0, 1);
addEdge(0, 4);
addEdge(1, 2);
addEdge(1, 3);
addEdge(1, 4);
addEdge(2, 3);
addEdge(3, 4);
cout << sizeof(AdjMatr) << " " << sizeof(rowSize*p);
printMat();
system("pause");
delete AdjMatr;
delete AdjMatRows;
Вернуться >>
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 35
Спасибо за внимание!
Максименкова Ольга Вениаминовна
Старший преподаватель Департамента программной инженерии, ФКН
E-mail: omaksimenkova@hse.ru
Blog: Stop To Scale (http://stoptoscale.blogspot.ru)

Представление графов в памяти компьютера (c++).

  • 1.
    Представление графов впамяти компьютера (с примерами на C++) Максименкова Ольга Вениаминовна Старший преподаватель Департамента программной инженерии Факультета компьютерных наук (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 1
  • 2.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 2 const int N = 3; const int M = 5; const int K = 7; int main() { int multiArr[N][M][K] = { 1, 2, 3, 4, 5, 6, 7, 8 }; for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) for (int k = 0; k < K; k++) cout << multiArr[i][j][k] << " "; return 0; } int arr[10]; // определён массив из 10 элементов for (int i = 0;i < 10;i++) cout << arr[i] << " "; return 0; -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Здесь есть инициализация! А здесь нет! Если заменить arr[i] на (arr+i), можно убедится, что адреса разные. Но *(arr+i) даст такой же вывод.
  • 3.
    Цели лекции (с) МаксименковаО.В., НИУ ВШЭ, ФКН, ДПИ 3 Рассмотреть • Варианты представления графов в памяти компьютера • Некоторые способы реализации этих представлений на языке C++ Выявить • Способы повышения быстродействия и экономии памяти для частных случаев
  • 4.
    Соглашения о терминологии (с)Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 4 Мультиграф [multigraph] – граф, содержащий кратные рёбра. Незнанов А.А., Кохов В.А. Алгоритмизация решения переборных задач анализа графов – М.: Издательский дом МЭИ, 2007. – 80 с. Граф – неориентированный граф без петель и кратных рёбер. Обозначение графа: G = (V, E), где идентификаторами (номерами) вершин и ребер выступают числа натурального ряда:  V = {v1, v2, … , vp} = {0, 1, … , p1}, p = |V| – число вершин;  E = {e1, e2, … , eq} = {0, 1, … , q1}, q = |E| – число ребер. Петля [loop] – ребро, инцидентное только одной вершине (соединяет вершину с самой собой). Кратными (или мультирёбрами) [multiple] называются рёбра, инцидентные одной и той же паре вершин. Две вершины смежны [adjacent], если они соединены ребром. Два ребра смежны [adjacent], если они имеют общую вершину.
  • 5.
    Базовые представления Индексные представленияграфа/орграфа в памяти компьютера (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 5
  • 6.
    Матрица смежности (с) МаксименковаО.В., НИУ ВШЭ, ФКН, ДПИ 6 Матрица смежности графа – квадратная матрица A с числом строк и столбцов, равным p. Элемент Ai j = 1, если существует дуга (i, j), в противном случае Ai j = 0. Для мультиграфов вместо 1 заносится кратность мультиребра. Объём памяти p2·a, где a – размер элемента матрицы int mtr[n][n] = { {0,1,0,0,1}, {1,0,1,1,1}, {0,1,0,1,0}, {0,1,1,0,1}, {1,1,0,1,0} }; cout << n*n*sizeof(int); 0 1 0 0 1 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 1 1 0 1 0 1 2 3 4 5 1 2 3 4 5 Для графов с весами на дугах, вместо 1 заносится вес ребра. Как перепишется матрица смежности для примера выше? 5 1 2 34 1 7 2 3 4 5 6
  • 7.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 7 5 2 34 4 7 12 3 5 6 9 8 0 1 0 0 1 1 0 2 0 1 0 2 0 2 0 0 0 2 0 2 1 1 0 2 0 1 2 3 4 5 1 2 3 4 5 Мультиграф int mtr[n][n] = { {0,1,0,0,1}, {1,0,2,0,1}, {0,2,0,2,0}, {0,0,2,0,2}, {1,1,0,2,0} }; cout << n*n*sizeof(int); Для всех видов графов веса вершин задают на главной диагонали матрицы A или в виде дополнительного массива WV.
  • 8.
    На чём можносэкономить? (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 8 Для обыкновенного графа допустимо хранение только части матрицы смежности – над главной диагональю. int main() { int** mtrSeg = new int*[n]; for (int i = 0; i < n; i++) *(mtrSeg + i) = new int[n - i]; mtrSeg[0][0] = mtrSeg[0][3] = 1; mtrSeg[0][1] = mtrSeg[0][2] = 0; mtrSeg[1][0] = mtrSeg[1][1] = mtrSeg[1][2] = 1; mtrSeg[2][0] = 1; mtrSeg[2][1] = 0; mtrSeg[3][0] = 1; for (int i = 0; i < n; i++) { // вывод cout << "n"; for (int j = 0; j < n - i - 1; j++) cout << *(*(mtrSeg + i)+j); } 0 1 0 0 1 1 0 1 1 1 0 1 0 1 0 0 1 1 0 1 1 1 0 1 0 1 2 3 4 5 1 2 3 4 5
  • 9.
    На чём можносэкономить? (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 9 При отсутствии весов можно использовать битовую матрицу (каждый элемент занимает один бит). Brendan McKay and Adolfo Piperno. nauty and Traces (http://pallini.di.uniroma1.it) Посмотреть вариант реализации подробно… cout << "Memory size: " << sizeof(AdjMatr) + sizeof(rowSize*p); Memory size: 8
  • 10.
    FO и FI-представления (с)Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 10 Для неориентированных графов определено только FO-представление, реализуемое одним одномерным массивом. 5 2 5 0 13 4 5 0 4 2 0 3 2 50 1 2 4 0 Количество вершин графа (p) Номера вершин, смежных с первой Номера вершин, смежных со второй Разделитель (ноль) Если нумерация вершин начинается с нуля, роль разделителя играет другой символ, например -1. Длина массива FO: 1 + 2·q + p, где q – количество рёбер, а p – количество вершин графа. 5 1 2 34 1 7 2 3 4 5 6
  • 11.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 11 #include <iostream> using namespace std; // число вершин const int p = 5; // число рёбер const int q = 7; int main() { int FO[1 + 2 * q + p] = { 5,2,5,0, 1,3,4,5,0, 4,2,0, 3,2,5,0, 1,2,4,0 }; cout << "nNode: " << 1 << "nt"; for (int i = 0, j = 1; i < 1 + 2 * q + p;i++) { if (FO[i] == 0) { j++; cout << "nNode: "<< j << "nt"; continue; } else cout << FO[i] << " "; } return 0; }
  • 12.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 12 Варианты для орграфа: 1. для каждой вершины записываются номера вершин, в которые из этой вершины исходят дуги (FO-представление), 2. Для каждой вершины записываются номера вершин, из которых исходят дуги в эту вершину (FI-представление). Длина массивов FO и FI равна 1 + q + p. 5 1 2 34 1 7 2 3 4 5 6 Задание на 5 минут: Напишите FO и FI представления для этого орграфа. В качестве разделителя используйте ноль. Ответ: FO 5 2 5 0 3 4 5 0 4 0 0 4 0 FI 5 0 1 0 2 0 2 5 3 0 1 2 0 На практических занятиях реализуйте данное представление на языке C++. Для каждой вершины вычислите абсолютную разность сумм весов входящих и выходящих рёбер. Результат вывести на экран.
  • 13.
    MFO и MFI-представления (с)Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 13 Для неориентированных графов определено только MFO-представление. 5 1 2 34 1 7 2 3 4 5 6 Номера вершин, смежных с первой Номера вершин, смежных со второй Длина массива ME равна 2 · q. Длина массива MV равна p + 1 MFO = ME 2 5 1 3 4 5 4 2 3 2 5 1 2 4 MV 0 2 6 8 11 14 P 5 Индекс последнего элемента ME плюс 1 Индекс первого элемента ME, смежного с первой вершиной Индекс первого элемента ME, смежного со второй вершиной
  • 14.
    Пример реализации (с) МаксименковаО.В., НИУ ВШЭ, ФКН, ДПИ 14 #include <iostream> using namespace std; // число вершин const int p = 5; // число рёбер const int q = 7; int main() { int ME[2 * q] = {2,5,1,3,4,5,4,2,3,2,5,1,2,4}; int MV[p + 1] = { 0,2,6,8,11,14 }; // цикл по вершинам for (int i = 0; i < p; i++) { cout << "Node " << i << ":nt"; // перебор вершин, смежных с данной (соседей) for (int j = MV[i]; j < MV[i + 1];j++) cout << ME[j] << " "; cout << "n"; } return 0; } 5 1 2 34 1 7 2 3 4 5 6
  • 15.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 15 Длина массива ME равна q. Длина массива MV равна p + 1 5 1 2 34 1 7 2 3 4 5 6 Варианты для орграфа: 1. FO-представление записывается в виде двух массивов (выходящие рёбра) 2. FI-представление записывается в виде двух массивов (входящие рёбра) Задание на 5 минут: Напишите MFO представление для этого орграфа. Ответ: MFI = ME 1 2 2 3 5 1 2 MV 0 0 1 2 3 5 7 P 5 MFO = ME 2 5 3 4 5 4 4 MV 0 2 5 6 6 7 P 5 На практических занятиях реализуйте данное представление на языке C++.
  • 16.
    На чём можносэкономить? (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 16 В массивы FO и ME для каждой вершины записываются только те номера вершин, которые не меньше (или не больше) номера этой вершины. Это позволяет уменьшить размер массива FO c (1+2q+p) до (1+q+p), а массива ME – с 2q до q. Для неориентированных графов допустимы сокращённые FO- и MFO- представления (BFO и BMFO) BFO 5 2 5 0 34 5 0 4 0 5 0 0 5 1 2 34 1 7 2 3 4 5 6 FO 5 2 5 0 13 4 5 0 4 2 0 3 2 50 1 2 4 0 Сравните:
  • 17.
    Матрица инциденций (с) МаксименковаО.В., НИУ ВШЭ, ФКН, ДПИ 17 Матрица инциденций графа – прямоугольная матрица В с числом строк p и числом столбцов q. Каждый столбец соответствует одному из рёбер. Столбец, соответствующий ребру e = {i, j} содержит 1 в i-й и j-й строке, в остальных строках содержатся нули. Столбец, соответствующий петле, содержит единственную 1. Для орграфа начало и конец дуги задаются разными числами (например, –1 – начало, 1 – конец). Для мультиграфа можно либо рассматривать каждое ребро в составе мультиребра как отдельное (с записью в отдельный столбец), либо записывать значение кратности ребра вместо 1. Представление занимает объём памяти, равный pqa, где a – размер элемента матрицы. 5 1 2 34 1 7 2 3 4 5 6 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 1 1 1 0 1 0 0 0 1 1 2 3 4 5 1 2 3 4 5 6 7
  • 18.
    Примеры матриц инциденций (с)Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 18 5 1 2 34 1 7 2 3 4 5 6 1 1 0 0 0 0 0 0 -1 1 1 0 1 0 0 0 0 -1 1 0 0 0 0 0 0 -1 -1 -1 -1 0 -1 0 0 0 1 1 2 3 4 5 1 2 3 4 5 6 7 5 1 2 34 4 7 12 3 5 6 9 8 1 1 0 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 1 1 0 0 0 0 1 1 1 2 3 4 5 1 2 3 4 5 6 7 8 9 Мультиграф Орграф
  • 19.
    Массив рёбер (с) МаксименковаО.В., НИУ ВШЭ, ФКН, ДПИ 19 Массив рёбер графа – прямоугольная матрица C с двумя строками и числом столбцов q. Каждый столбец соответствует одному из рёбер. В столбце, соответствующем ребру e = {i, j} первый элемент содержит i, а второй – j. 5 1 2 34 1 7 2 3 4 5 6 1 2 2 2 3 4 5 2 3 4 5 4 5 1 q = 7 1 1 2 2 2 3 4 2 5 3 4 5 4 5 Отсортированный C = void setRib(rib& r, int a, int b) { r.beg = a; r.end = b; } struct rib { int beg; int end; }; rib C[q];
  • 20.
  • 21.
    Списки смежности (с) МаксименковаО.В., НИУ ВШЭ, ФКН, ДПИ 21 2 Указатель на граф 4 NULL 1 3 NULL NULL 2 4 NULL 4 1 2 NULL3 1 24 12 3 4 5 3 Список LV содержит ссылки на списки смежности отдельных вершин LEi. Каждый список смежности LEi– список (обычно односвязный) номеров вершин, смежных c вершиной i.
  • 22.
    Организация списков смежности (с)Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 22 // элемент списка смежности struct AdjList { AdjList* next; // следующий элемент списка int w; // номер вершины }; // вершина графа struct VerList { AdjList* head; // указатель на начало списка смежности VerList* next; // следущая вершина }; Односвязные списки, построенные при помощи структур
  • 23.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 23 int main() { VerList LVtmp; VerList* LVhead=&LVtmp; // указатель на начало списка // первая смежная с первой вершина AdjList ELtmp1; ELtmp1.next = NULL; ELtmp1.w = 2; // вторая смежная с первой вершина AdjList newEL; newEL.next = NULL; newEL.w = 4; // добавили вторую в список ELtmp1.next = &newEL; // связываем список смежности с первой вершиной LVtmp.head = &ELtmp1; LVtmp.next = NULL; cout << LVtmp.head->w << " "; cout << LVtmp.head->next->w; return 0; } Очень подробный пример очень нереального кода 2 4 NULL Требуется декомпозиция!
  • 24.
  • 25.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 25 Объект-вершина Объект-ребро Edges Веса Edges Веса Edges Веса Edges Веса 1 2 3 4 SourceV1 DestV SourceV5 DestV SourceV4 DestV SourceV3 DestV SourceV2 DestV Веса Веса Веса Веса Веса 1 24 12 3 4 5 3
  • 26.
    Объектно-ориентированная библиотека для работыс графами (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 26 Boost Graph Library (BGL). Graph interface (http://www.boost.org/doc/libs/1_58_0/libs/graph/doc/graph_concepts.html)
  • 27.
    Рекомендации по применению представлений (с)Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 27 Применение матрицы смежности является оправданным, когда: 1) число вершин невелико (p  1000), а число рёбер велико (стандартная оценка для обыкновенного графа: > p(p1)/4); 2) когда необходимо иметь быстрый доступ к произвольным рёбрам графа; 3) когда часто необходимо добавлять и удалять рёбра при неизменном числе вершин. Когда трансформация графа не требуется, хорошим компромиссом для графов общего вида является MFO-представление и его варианты (списки смежности и др.). Матрица инциденций – самое невыгодное с алгоритмической точки зрения представление графа.
  • 28.
    Сложность базовых операцийпри различных представлениях графа (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 28 № Представление Асимптотическая сложность операций IsEdge AddEdge ForAllAdj 1 Матрица смежности 1 1 p 2 Матрица инциденций q p+alloc pq 3 Массив рёбер q alloc q 4 Отсортированный массив рёбер log(q) q+alloc log(q)+de g(i) 5 FO-представление p+q p+q+alloc p+q 6 MFO-представление max(deg(i), deg(j)) q+alloc deg(i) 7 Отсортированное MFO-представление max(log(deg(i )), log(deg(j))) q+alloc deg(i)
  • 29.
  • 30.
    Вариант реализации матрицысмежности через битовую матрицу (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 30 #include <iostream> using namespace std; // число вершин графа const unsigned int p = 5; // размер unsigned int в битах const unsigned int ElSize = sizeof(unsigned int) << 3; // Двоичный логарифм от размера unsigned int в битах const unsigned int LogElSize = log2(sizeof(unsigned int)) + 3; // длина строки битовой матрицы в unsigned int const unsigned int rowSize = (p + (sizeof(unsigned int) << 3) - 1) >> LogElSize; // массив указателей на строки матрицы смежности unsigned int* AdjMatRows[p]; // указатель на саму битовую матрицу unsigned int* AdjMatr; 5 1 2 34
  • 31.
    Выделение памяти подбитовую матрицу (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 31 int main() { // выделяем память под матрицу смежности AdjMatr = new unsigned int[rowSize*p]; // зануляем элементы for (int i = 0; i < rowSize*p; AdjMatr[i] = 0,i++); // связываем указатели на строки матрицы с участками памяти *AdjMatRows = AdjMatr; for (int i = 1; i < p; i++) AdjMatRows[i] = AdjMatRows[i - 1]+ rowSize; // здесь добавляем рёбра, вычисления, что угодно... delete AdjMatr; delete AdjMatRows; return 0; }
  • 32.
    Добавления ребра… Кудапоставить 1? (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 32 // функция добавления ребра между вершинами a и b void addEdge(int a, int b) { // номера вершин // находим нужный uint в строке a unsigned int w = AdjMatRows[a][b >> LogElSize]; // проверяем бит с номером остаток от деления b на число бит в unsigned int unsigned int e = 1 << (b & (ElSize - 1)); if (!(w & e)) { // добавляем A[a,b] AdjMatRows[a][b >> LogElSize] = w | e; // добавляем A[b,a] w = AdjMatRows[b][a >> LogElSize]; e = 1 << (a & (ElSize - 1)); AdjMatRows[b][a >> LogElSize] = w | e; } }
  • 33.
    Функция печати битовойматрицы (с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 33 // функция печати матрицы смежности void printMat() { for (int i = 0; i < p; i++) { // вывод cout << "n"; for (int j = 0; j < rowSize; j++) // битовое представление строки for (int k = 0; k < p; k++) cout << ((AdjMatRows[i][j] >> k) & 1); } cout << "n"; } На практических занятиях: 1) запустите код и протестируйте его для матриц смежности графов с 32 и более вершинами. 2) допишите функцию удаления ребра между вершинами a и b.
  • 34.
    Окончание функции main() (с)Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 34 addEdge(0, 1); addEdge(0, 4); addEdge(1, 2); addEdge(1, 3); addEdge(1, 4); addEdge(2, 3); addEdge(3, 4); cout << sizeof(AdjMatr) << " " << sizeof(rowSize*p); printMat(); system("pause"); delete AdjMatr; delete AdjMatRows; Вернуться >>
  • 35.
    (с) Максименкова О.В.,НИУ ВШЭ, ФКН, ДПИ 35 Спасибо за внимание! Максименкова Ольга Вениаминовна Старший преподаватель Департамента программной инженерии, ФКН E-mail: omaksimenkova@hse.ru Blog: Stop To Scale (http://stoptoscale.blogspot.ru)