-2

我开发了一个小程序,它在图形之间随机生成多个连接(计数的值也可以是随机的,但是为了测试目的我已经定义了const value,它可以随时重新定义为随机值)。

代码是 C#:http: //ideone.com/FDCtT0

(结果:成功时间:0.04s 内存:36968 kB 返回值:0)

如果您不知道什么是邻接矩阵,请访问此处:http ://en.wikipedia.org/wiki/Adjacency_matrix

在此处输入图像描述

我认为,我的代码版本没有经过优化。如果我要使用大小为:10k x 10k的大型矩阵。

  1. 您有什么建议,在此任务中如何更好地并行计算?我是否应该使用信号量等一些储物柜模型来对大型矩阵进行多线程计算。

  2. 您对重新设计程序架构有什么建议。我应该如何为大型矩阵做准备?

  3. 如您所见,在ideone上,我展示了时间执行参数并在 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

I will start from the end, if you don't mind. :)

3) Of course, it is O(n^2). As well as the memory usage.

2) Since sizeof(bool) == 1 byte, not bit, you can optimize memory usage by using bit masks instead of raw bool values, this will make it (8 bits per bool)^2 = 64 times less.

1) I don't know C# that well, but as i just googled i found out that C# primitive types are atomic, which means you can safely use them in multi-threading. Then, you are to make a super easy multi-threading task: just split your graphs by threads and press the 'run' button, which will run every thread with its part of graph on itself. They are independent so that's not going to be any problem, you don't need any semaphores, locks and so on.

The thing is that you won't be able to have an adjacency matrix with size 10^9 x 10^9. You just can't store it in the memory. But, there is an other way.
Create an adjacency list for each vertex, which will have a list of all vertices it is connected with. After building those lists from your graph, sort those lists for each vertex. Then, you can answer on the 'is a connected to b' in O( log(size of adjacency list for vertex a) ) time by using binary search, which is really fast for common usage.

Now, if you want to implement Dijkstra algorithm really fast, you won't need an adj. matrix at all, just those lists.

同样,这一切都取决于未来的任务和约束。您不能存储该大小的矩阵,仅此而已。Dijkstra 或 BFS 不需要它,这是事实。:) 从图的角度来看,在概念上没有区别:无论它存储在什么数据结构中,图都是相同的。

如果您真的想要矩阵,那么这就是解决方案:
我们知道,连接数(1在矩阵中)远小于其最大值 n^2。通过执行这些列表,我们只需存储1(也称为稀疏矩阵)的位置,这不会消耗不必要的内存。

于 2012-12-06T22:23:14.130 回答