-2

グラフ間のいくつかの接続をランダムに生成する小さなプログラムを開発しました(カウントの値もランダムにすることができますが、テストの目的のためにconst valueを定義しました。いつでもランダム値で再定義できます)。

コードは C# です: http://ideone.com/FDCtT0

( 結果: 成功時間: 0.04 秒 メモリ: 36968 kB 戻り値: 0 )

隣接行列がわからない場合は、ここにアクセスしてください: http://en.wikipedia.org/wiki/Adjacency_matrix

ここに画像の説明を入力

私のコードのバージョンはかなり最適化されていないと思います。サイズが10k x 10kの大きな行列で作業する場合。

  1. あなたの提案は何ですか?このタスクで計算を並列化するにはどうすればよいですか? 大規模な行列でのマルチスレッド計算には、セマフォなどのロッカー モデルを使用する必要があります。

  2. プログラムのアーキテクチャを再設計するための提案は何ですか。大規模なマトリックス用にどのように準備すればよいですか?

  3. ご覧のとおり、上のideoneでは、time 実行パラメーターと RAM に割り当てられたメモリを示しています。私のプログラムの実行の漸近値は何ですか? O(n^2)ですか?

だから私はあなたのアドバイスを聞きたいです漸近マーク、セマフォを使用した並列計算(またはスレッドのより良いロッカーモデル)を増やす方法。

ありがとうございました!

PS: SO では、フォーマットされたコードなしでトピックを投稿することは許可されていないため、最後に投稿しています (完全なプログラム):

/*
    Oleg Orlov, 2012(c), generating randomly adjacency matrix and graph connections
*/

using System;
using System.Collections.Generic;

class Graph
{
    internal int id;
    private int value;
    internal Graph[] links;

    public Graph(int inc_id, int inc_value)
    {
        this.id = inc_id;
        this.value = inc_value;
        links = new Graph[Program.random_generator.Next(0, 4)];
    }
}

class Program
{
    private const int graphs_count = 10;
    private static List<Graph> list;
    public static Random random_generator;

    private static void Init()
    {
        random_generator = new Random();
        list = new List<Graph>(graphs_count);

        for (int i = 0; i < list.Capacity; i++)
        {
            list.Add(new Graph(i, random_generator.Next(100, 255) * i + random_generator.Next(0, 32)));
        }
    }

    private static void InitGraphs()
    {
        for (int i = 0; i < list.Count; i++)
        {
            Graph graph = list[i] as Graph;
            graph.links = new Graph[random_generator.Next(1, 4)];

            for (int j = 0; j < graph.links.Length; j++)
            {
                graph.links[j] = list[random_generator.Next(0, 10)];
            }

            list[i] = graph;
        }
    }

    private static bool[,] ParseAdjectiveMatrix()
    {
        bool[,] matrix = new bool[list.Count, list.Count];

        foreach (Graph graph in list)
        {
            int[] links = new int[graph.links.Length];

            for (int i = 0; i < links.Length; i++)
            {
                links[i] = graph.links[i].id;
                matrix[graph.id, links[i]] = matrix[links[i], graph.id] = true;
            }
        }

        return matrix;
    }

    private static void PrintMatrix(ref bool[,] matrix)
    {
        for (int i = 0; i < list.Count; i++)
        {
            Console.Write("{0} | [ ", i);

            for (int j = 0; j < list.Count; j++)
            {
                Console.Write(" {0},", Convert.ToInt32(matrix[i, j]));
            }

            Console.Write(" ]\r\n");
        }

        Console.Write("{0}", new string(' ', 7));

        for (int i = 0; i < list.Count; i++)
        {
            Console.Write("---");
        }

        Console.Write("\r\n{0}", new string(' ', 7));

        for (int i = 0; i < list.Count; i++)
        {
            Console.Write("{0}  ", i);
        }

        Console.Write("\r\n");
    }

    private static void PrintGraphs()
    {
        foreach (Graph graph in list)
        {
            Console.Write("\r\nGraph id: {0}. It references to the graphs: ", graph.id);

            for (int i = 0; i < graph.links.Length; i++)
            {
                Console.Write(" {0}", graph.links[i].id);
            }
        }
    }

    [STAThread]
    static void Main()
    {
        try
        {
            Init();
            InitGraphs();
            bool[,] matrix = ParseAdjectiveMatrix();
            PrintMatrix(ref matrix);
            PrintGraphs();
        }
        catch (Exception exc)
        {
            Console.WriteLine(exc.Message);
        }

        Console.Write("\r\n\r\nPress enter to exit this program...");
        Console.ReadLine();
    }
}
4

1 に答える 1

2

差し支えなければ、最後から始めます。:)

3) もちろんですO(n^2)。メモリ使用量も同様です。

2)sizeof(bool) == 1 byte, not bit生の bool 値の代わりにビット マスクを使用してメモリ使用量を最適化できるため、(8 bits per bool)^2 = 64時間は短縮されます。

1)私はC#をよく知りませんが、グーグルで調べたところ、C#のプリミティブ型はアトミックであることがわかりました。つまり、マルチスレッドで安全に使用できます。次に、非常に簡単なマルチスレッド タスクを作成します。グラフをスレッドごとに分割し、[実行] ボタンを押すだけで、すべてのスレッドがグラフの一部とともに実行されます。それらは独立しているため、問題にはなりません。セマフォやロックなどは必要ありません。

問題は、サイズが 10^9 x 10^9 の隣接行列を持つことができないということです。メモリに保存することはできません。しかし、別の方法があります。各頂点の隣接リスト
を 作成します。これには、接続されているすべての頂点のリストが含まれます。グラフからこれらのリストを作成したら、それらのリストを頂点ごとに並べ替えます。次に、二分探索を使用して「に接続されています」に間に合うように答えることができます。これは、一般的な使用法としては非常に高速です。abO( log(size of adjacency list for vertex a) )

ダイクストラ アルゴリズムを非常に高速に実装する場合は、adj は必要ありません。これらのリストだけです。

繰り返しますが、それはすべて将来のタスクと制約に依存します。そのサイズの行列を保存することはできません。それだけです。Dijkstra や BFS には必要ありません。これは事実です。:) グラフ側との概念的な違いはありません。グラフは、格納されているデータ構造に関係なく同じです。

本当にマトリックスが必要な場合は、それが解決策です。接続の数 (マトリックス内) は、最大値である n^2 よりもはるかに小さいことが
わかっています。これらのリストを実行することで、 (スパース行列とも呼ばれます) の1位置を単純に格納し、不要なメモリを消費しません。1

于 2012-12-06T22:23:14.130 に答える