Многомерный массив создает хорошее линейное расположение памяти, в то время как зубчатый массив подразумевает несколько дополнительных уровней абстракции.
Поиск значения jagged[3][6]
в зубчатом массиве var jagged = new int[10][5]
работы как это: Ищите элемент в индексе 3 (который является массивом), и ищите элемент в индексе 6 в том массиве (который является значением). Для каждого размера в этом случае, существует дополнительный взгляд (это - дорогой шаблон доступа к памяти).
многомерный массив А размечается линейно в памяти, фактическое значение найдено путем умножения вместе индексов. Однако, учитывая массив var mult = new int[10,30]
, Length
свойство того многомерного массива возвращает общее число элементов т.е. 10 * 30 = 300.
Rank
свойство зубчатого массива всегда равняется 1, но многомерный массив может иметь любой разряд. GetLength
метод любого массива может использоваться для получения длины каждого размера. Для многомерного массива в этом примере mult.GetLength(1)
возвраты 30.
Индексация многомерного массива быстрее. например, учитывая многомерный массив в этом примере mult[1,7]
= 30 * 1 + 7 = 37, получите элемент в том индексе 37. Это - лучший шаблон доступа к памяти, потому что только одна ячейка памяти включена, который является базовым адресом массива.
многомерный массив А поэтому выделяет непрерывный блок памяти, в то время как зубчатый массив не должен быть квадратным, например, jagged[1].Length
не должен равняться jagged[2].Length
, который был бы верен для любого многомерного массива.
Производительность мудрые, многомерные массивы должны быть быстрее. Намного быстрее, но из-за действительно плохой реализации CLR они не.
23.084 16.634 15.215 15.489 14.407 13.691 14.695 14.398 14.551 14.252
25.782 27.484 25.711 20.844 19.607 20.349 25.861 26.214 19.677 20.171
5.050 5.085 6.412 5.225 5.100 5.751 6.650 5.222 6.770 5.305
первая строка является синхронизациями зубчатых массивов, вторых выставочных многомерных массивов и третьего, хорошо это - то, как это должно быть. Программу показывают ниже, к вашему сведению это было протестировано, работая моно. (Синхронизации окон весьма отличаются, главным образом из-за изменений реализации CLR).
окна On, синхронизации зубчатых массивов значительно выше о том же как моя собственная интерпретация того, какой многомерный массив ищут, должен быть похожим, видеть 'Единственный ()'. Печально JIT-компилятор окон действительно глуп, и это, к сожалению, делает эти обсуждения производительности трудными, существует слишком много несоответствий.
Это синхронизации, я вошел в окна, то же соглашение здесь, первая строка являются зубчатыми массивы, вторые многомерный и третий моя собственная реализация многомерных, отмечают, насколько медленнее это находится на окнах по сравнению с моно.
8.438 2.004 8.439 4.362 4.936 4.533 4.751 4.776 4.635 5.864
7.414 13.196 11.940 11.832 11.675 11.811 11.812 12.964 11.885 11.751
11.355 10.788 10.527 10.541 10.745 10.723 10.651 10.930 10.639 10.595
Исходный код:
using System;
using System.Diagnostics;
static class ArrayPref
{
const string Format = "{0,7:0.000} ";
static void Main()
{
Jagged();
Multi();
Single();
}
static void Jagged()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var jagged = new int[dim][][];
for(var i = 0; i < dim; i++)
{
jagged[i] = new int[dim][];
for(var j = 0; j < dim; j++)
{
jagged[i][j] = new int[dim];
for(var k = 0; k < dim; k++)
{
jagged[i][j][k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
static void Multi()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var multi = new int[dim,dim,dim];
for(var i = 0; i < dim; i++)
{
for(var j = 0; j < dim; j++)
{
for(var k = 0; k < dim; k++)
{
multi[i,j,k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
static void Single()
{
const int dim = 100;
for(var passes = 0; passes < 10; passes++)
{
var timer = new Stopwatch();
timer.Start();
var single = new int[dim*dim*dim];
for(var i = 0; i < dim; i++)
{
for(var j = 0; j < dim; j++)
{
for(var k = 0; k < dim; k++)
{
single[i*dim*dim+j*dim+k] = i * j * k;
}
}
}
timer.Stop();
Console.Write(Format,
(double)timer.ElapsedTicks/TimeSpan.TicksPerMillisecond);
}
Console.WriteLine();
}
}
Я думаю, что то, что вы ищете, обычно называется Заливкой . Вам решать, проходить ли вы по графику через BFS или DFS.
Обычно вы берете немаркированный (также известный как неокрашенный) узел и назначаете ему новую метку. Вы назначаете одну и ту же метку всем узлам, смежным с этим, и так далее всем узлам, доступным с этого узла.
Когда никакие другие достижимые узлы не могут быть помечены, вы начинаете с выбора другого непомеченного узла. Обратите внимание, что тот факт, что этот новый узел не помечен, означает, что он недоступен из нашего предыдущего узла и, следовательно, находится в другом отключенном компоненте.
Когда больше нет немаркированных узлов, количество различных меток, которые вы должны были использовать, равно количеству компонентов графа. Метка для каждого узла сообщает вам, какой узел является частью какого компонента.
Есть много аспектов этого вопроса, которые полностью не объяснены, поэтому я дам исчерпывающий ответ. Несмотря на мою склонность размещать стены с текстом. : / Также обратите внимание, что я предполагаю, что это вопрос домашнего задания или вопрос для самообразования, поэтому я не собираюсь давать прямой ответ.
Два основных алгоритма для определения связности графа: Поиск в глубину и Поиск в ширину . Это две отправные точки, на которые стоит обратить внимание. Оба приведут вас к решению, но по-разному, и трудно спорить, что «лучше», не рассматривая некоторые довольно глубокие аспекты проблемы. Но давайте двигаться дальше.
Как я уже упоминал ранее, вы упустили некоторые важные детали, а я ' Я коснусь некоторых возможностей здесь.
Ваш граф направлен или неориентирован? и рассматриваете ли вы возможность подключения в «сильном» смысле (в этом случае см. ответ Огги) или возможность подключения в «слабом» смысле? В зависимости от вашего ответа вам придется подойти к вашему алгоритму несколько иначе. Обратите внимание, что для неориентированного графа слабая и сильная связность эквивалентны, так что это приятно. Но вы должны всегда помнить о структуре графа при реализации или нахождении алгоритма.
Кроме того, возникает вопрос, что вы подразумеваете под «поиском подграфов» (перефразирование). Обычно проблема подключения графа - это проблема решения - просто «есть один связанный граф» или «есть два или более подграфа (иначе говоря, он отключен)». Наличие алгоритма для этого требует минимум работы с книгами, что приятно. :) Следующим шагом будет подсчет графиков, буквально количество их, и это книжное дело тоже не так уж и плохо. В конце концов, вам может понадобиться список узлов в каждом подграфе. Наконец, вы можете захотеть буквально скопировать подграфы, ребра и все остальное (так что возвращаемым типом будет список графов, я полагаю, с подразумеваемым инвариантом, что каждый граф связан). Ни один из этих разных типов результатов не потребует другого алгоритма, но определенно потребует другого подхода к работе с книгами.
Все это может показаться нелепым излишеством для того, что является довольно простым вопрос, но я подумал, что просто выделю все аспекты, связанные даже с таким простым вопросом о графике. Как своего рода клиффхэнг, обратите внимание, что ничто из этого еще не касается времени выполнения или использования памяти! :) - Агор
JGraphT - хорошая графическая библиотека с открытым исходным кодом, работающая под лицензией LGPL. Я использовал его в прошлом, чтобы работать с графиками и обнаруживать циклы внутри графиков. Он также довольно прост в использовании, и вы можете использовать JGraph для визуализации графиков.
Полагаю, вы хотите найти все (сильно) связанные компоненты? Для этого вы можете использовать алгоритм Тарьяна (вариант DFS)
Как насчет поиска в ширину, чтобы найти все подключенные узлы? Когда у вас есть список подключенных узлов, вы вычтите этот список из списка всех узлов. Вы получите список отключенных узлов
Я столкнулся с похожей проблемой, когда мне нужны были все слабосвязные подграфы направленного графа. Я писал об этом в блоге здесь. Я использовал API JUNG и сравнил два подхода. Мой первый подход можно использовать как шаблон для решения вашей проблемы.