Нахождение всех разъединенных подграфов в графике

Многомерный массив создает хорошее линейное расположение памяти, в то время как зубчатый массив подразумевает несколько дополнительных уровней абстракции.

Поиск значения 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();
    }
}
37
задан Ollie Glass 28 August 2009 в 19:06
поделиться

6 ответов

Я думаю, что то, что вы ищете, обычно называется Заливкой . Вам решать, проходить ли вы по графику через BFS или DFS.

Обычно вы берете немаркированный (также известный как неокрашенный) узел и назначаете ему новую метку. Вы назначаете одну и ту же метку всем узлам, смежным с этим, и так далее всем узлам, доступным с этого узла.

Когда никакие другие достижимые узлы не могут быть помечены, вы начинаете с выбора другого непомеченного узла. Обратите внимание, что тот факт, что этот новый узел не помечен, означает, что он недоступен из нашего предыдущего узла и, следовательно, находится в другом отключенном компоненте.

Когда больше нет немаркированных узлов, количество различных меток, которые вы должны были использовать, равно количеству компонентов графа. Метка для каждого узла сообщает вам, какой узел является частью какого компонента.

54
ответ дан 27 November 2019 в 04:25
поделиться

Есть много аспектов этого вопроса, которые полностью не объяснены, поэтому я дам исчерпывающий ответ. Несмотря на мою склонность размещать стены с текстом. : / Также обратите внимание, что я предполагаю, что это вопрос домашнего задания или вопрос для самообразования, поэтому я не собираюсь давать прямой ответ.

Два основных алгоритма для определения связности графа: Поиск в глубину и Поиск в ширину . Это две отправные точки, на которые стоит обратить внимание. Оба приведут вас к решению, но по-разному, и трудно спорить, что «лучше», не рассматривая некоторые довольно глубокие аспекты проблемы. Но давайте двигаться дальше.

Как я уже упоминал ранее, вы упустили некоторые важные детали, а я ' Я коснусь некоторых возможностей здесь.

Ваш граф направлен или неориентирован? и рассматриваете ли вы возможность подключения в «сильном» смысле (в этом случае см. ответ Огги) или возможность подключения в «слабом» смысле? В зависимости от вашего ответа вам придется подойти к вашему алгоритму несколько иначе. Обратите внимание, что для неориентированного графа слабая и сильная связность эквивалентны, так что это приятно. Но вы должны всегда помнить о структуре графа при реализации или нахождении алгоритма.

Кроме того, возникает вопрос, что вы подразумеваете под «поиском подграфов» (перефразирование). Обычно проблема подключения графа - это проблема решения - просто «есть один связанный граф» или «есть два или более подграфа (иначе говоря, он отключен)». Наличие алгоритма для этого требует минимум работы с книгами, что приятно. :) Следующим шагом будет подсчет графиков, буквально количество их, и это книжное дело тоже не так уж и плохо. В конце концов, вам может понадобиться список узлов в каждом подграфе. Наконец, вы можете захотеть буквально скопировать подграфы, ребра и все остальное (так что возвращаемым типом будет список графов, я полагаю, с подразумеваемым инвариантом, что каждый граф связан). Ни один из этих разных типов результатов не потребует другого алгоритма, но определенно потребует другого подхода к работе с книгами.

Все это может показаться нелепым излишеством для того, что является довольно простым вопрос, но я подумал, что просто выделю все аспекты, связанные даже с таким простым вопросом о графике. Как своего рода клиффхэнг, обратите внимание, что ничто из этого еще не касается времени выполнения или использования памяти! :) - Агор

8
ответ дан 27 November 2019 в 04:25
поделиться

JGraphT - хорошая графическая библиотека с открытым исходным кодом, работающая под лицензией LGPL. Я использовал его в прошлом, чтобы работать с графиками и обнаруживать циклы внутри графиков. Он также довольно прост в использовании, и вы можете использовать JGraph для визуализации графиков.

3
ответ дан 27 November 2019 в 04:25
поделиться

Полагаю, вы хотите найти все (сильно) связанные компоненты? Для этого вы можете использовать алгоритм Тарьяна (вариант DFS)

2
ответ дан 27 November 2019 в 04:25
поделиться

Как насчет поиска в ширину, чтобы найти все подключенные узлы? Когда у вас есть список подключенных узлов, вы вычтите этот список из списка всех узлов. Вы получите список отключенных узлов

1
ответ дан 27 November 2019 в 04:25
поделиться

Я столкнулся с похожей проблемой, когда мне нужны были все слабосвязные подграфы направленного графа. Я писал об этом в блоге здесь. Я использовал API JUNG и сравнил два подхода. Мой первый подход можно использовать как шаблон для решения вашей проблемы.

1
ответ дан 27 November 2019 в 04:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: