Представление графов в памяти компьютера (c++)
TRANSCRIPT
Представление графов в памяти компьютера
(с примерами на 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 00 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 00 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, … , p1}, p = |V| – число вершин;
E = {e1, e2, … , eq} = {0, 1, … , q1}, 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
12345
1 2 3 4 5
Для графов с весами на дугах, вместо 1 заносится вес ребра. Как перепишется
матрица смежности для примера выше?
5
1
2
34
1
7
23
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
12345
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
12345
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 1 3 4 5 0 4 2 0 3 2 5 0 1 2 4 0
Количество
вершин графа
(p)
Номера вершин,
смежных с
первой
Номера вершин,
смежных со
второй
Разделитель
(ноль)
Если нумерация вершин начинается с нуля, роль разделителя играет другой символ,
например -1.
Длина массива FO: 1 + 2·q + p, где q – количество рёбер, а p – количество
вершин графа.
5
1
2
34
1
7
23
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 << "\n\t";for (int i = 0, j = 1; i < 1 + 2 * q + p;i++) {
if (FO[i] == 0) {j++;cout << "\nNode: "<< j << "\n\t";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
23
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 << ":\n\t";// перебор вершин, смежных с данной (соседей)for (int j = MV[i]; j < MV[i + 1];j++)
cout << ME[j] << " ";cout << "\n";
}return 0;
}
5
1
2
34
1
7
23
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+2q+p) до (1+q+p), а массива
ME – с 2q до q.
Для неориентированных графов допустимы сокращённые FO- и MFO-
представления (BFO и BMFO)
BFO 5 2 5 0 3 4 5 0 4 0 5 0 0
5
1
2
34
1
7
23
4
5
6
FO 5 2 5 0 1 3 4 5 0 4 2 0 3 2 5 0 1 2 4 0
Сравните:
Матрица инциденций
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 17
Матрица инциденций графа – прямоугольная матрица В с числом строк p и
числом столбцов q. Каждый столбец соответствует одному из рёбер. Столбец,
соответствующий ребру e = {i, j} содержит 1 в i-й и j-й строке, в остальных строках
содержатся нули. Столбец, соответствующий петле, содержит единственную 1.
Для орграфа начало и конец дуги задаются разными числами (например, –1 –
начало, 1 – конец).
Для мультиграфа можно либо рассматривать каждое ребро в составе мультиребра
как отдельное (с записью в отдельный столбец), либо записывать значение
кратности ребра вместо 1.
Представление занимает объём памяти, равный pqa, где a – размер
элемента матрицы.
5
1
2
34
1
7
23
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
12345
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
12345
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
12345
1 2 3 4 5 6 7 8 9
Мультиграф
Орграф
Массив рёбер
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 19
Массив рёбер графа – прямоугольная матрица C с двумя строками и числом
столбцов q.
Каждый столбец соответствует одному из рёбер.
В столбце, соответствующем ребру e = {i, j} первый элемент содержит i, а второй
– j.
5
1
2
34
1
7
23
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];
Списки смежности
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 21
2
Указатель на граф
4 NULL
1 3
NU
LL
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
Требуется декомпозиция!
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 25
Объект-вершинаОбъект-ребро
Edges
Веса
Edges
Веса
Edges
Веса
Edges
Веса
1
2
3
4
SourceV1
DestV
SourceV5
DestV
SourceV4
DestV
SourceV3
DestV
SourceV2
DestV
Веса
Веса
Веса
Веса
Веса
124
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(p1)/4);
2) когда необходимо иметь быстрый доступ к произвольным рёбрам графа;
3) когда часто необходимо добавлять и удалять рёбра при неизменном числе
вершин.
Когда трансформация графа не требуется, хорошим компромиссом для графов
общего вида является MFO-представление и его варианты (списки смежности
и др.).
Матрица инциденций – самое невыгодное с алгоритмической
точки зрения представление графа.
Сложность базовых операций при различных представлениях графа
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 28
№ Представление
Асимптотическая сложность
операций
IsEdge AddEdge ForAllAdj
1 Матрица смежности 1 1 p
2 Матрица инциденций q p+alloc pq
3 Массив рёбер q alloc q
4 Отсортированный массив рёбер log(q) q+alloclog(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)
Вариант реализации матрицы смежности через битовую матрицу
(с) Максименкова О.В., НИУ ВШЭ, ФКН, ДПИ 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 intconst 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 и bvoid addEdge(int a, int b) { // номера вершин
// находим нужный uint в строке aunsigned int w = AdjMatRows[a][b >> LogElSize];// проверяем бит с номером остаток от деления b на число
бит в unsigned intunsigned 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: [email protected]
Blog: Stop To Scale (http://stoptoscale.blogspot.ru)