C#中链接的2D矩阵

时间:2010-11-26 07:51:28

标签: c# matrix

我需要在C#中实现这个场景:

http://i.stack.imgur.com/Dm6G3.jpg

矩阵将非常大,可能是10000x10000或更大。我将在分层聚类算法中将其用于距离矩阵。在算法的每次迭代中,矩阵都应该更新(将2行连接成1和2列为1)。如果我使用简单的双[,]或双[] []矩阵,这个操作将非常“昂贵”。 请问,任何人都可以建议这种情况的C#实现吗?

6 个答案:

答案 0 :(得分:1)

目前你有算法吗?那贵是什么意思?记忆还是时间昂贵?如果内存昂贵:你可以用c#做多少。但您可以考虑使用临时对象在数据库中执行计算。如果时间昂贵:您可以使用并行性来连接列和行。

但除此之外我认为一个简单的double[,]数组是你在c#中获得的最快和内存节省方式,因为访问数组值是一个o(1)操作,并且数组具有最少的内存和管理开销(与列表和词典相比)。

答案 1 :(得分:1)

如上所述,基本的双[,]将是在C#中处理此问题的最有效方法。

请记住,C#位于托管内存的顶层,因此与低级别(就内存而言)操作相比,您对细粒度的控制较少,与基本C类似。在C#中创建自己的对象以添加功能将在这种情况下只使用更多内存,并且可能会降低算法速度。

如果您尚未选择算法,CURE似乎是一个不错的选择。算法的选择可能会影响您的数据结构选择,但这不太可能。

您会发现该算法无论如何都能确定“成本”的理论极限。例如,您将阅读对于CURE,您受到O(n2 log n)运行时间和O(n)内存使用的约束。

我希望这会有所帮助。如果您能提供更多详细信息,我们可能会进一步提供帮助!

<磷>氮

答案 2 :(得分:1)

不可能“合并”两行或两列,你必须将整个矩阵复制到一个新的,较小的矩阵中,这确实是不可接受的昂贵。

您应该只将一行中的值添加到上一行,然后忽略这些值,就像删除它们一样。

数组的数组:double [] []实际上比double [,]更快。但需要更多的记忆。

如果稍微更改算法,可能不需要整个数组合并,但这可能有助于你:

    public static void MergeMatrix()
    {
        int size = 100;
        // Initialize the matrix
        double[,] matrix = new double[size, size];
        for (int i = 0; i < size; i++)
            for (int j = 0; j < size; j++)
                matrix[i, j] = ((double)i) + (j / 100.0);

        int rowMergeCount = 0, colMergeCount = 0;
        // Merge last row.
        for (int i = 0; i < size; i++)
            matrix[size - rowMergeCount - 2, i] += matrix[size - rowMergeCount - 1, i];
        rowMergeCount++;
        // Merge last column.
        for (int i = 0; i < size; i++)
            matrix[i, size - colMergeCount - 2] += matrix[i, size - colMergeCount - 1];
        colMergeCount++;

        // Read the newly merged values.
        int newWidth = size - rowMergeCount, newHeight = size - colMergeCount;
        double[,] smaller = new double[newWidth, newHeight];
        for (int i = 0; i < newWidth; i++)
            for (int j = 0; j < newHeight; j++)
                smaller[i, j] = matrix[i, j];

        List<int> rowsMerged = new List<int>(), colsMerged = new List<int>();
        // Merging row at random position.
        rowsMerged.Add(15);
        int target = rowsMerged[rowMergeCount - 1];
        int source = rowsMerged[rowMergeCount - 1] + 1;
        // Still using the original matrix since it's values are still usefull.
        for (int i = 0; i < size; i++)
            matrix[target, i] += matrix[source, i];
        rowMergeCount++;

        // Merging col at random position.
        colsMerged.Add(37);
        target = colsMerged[colMergeCount - 1];
        source = colsMerged[colMergeCount - 1] + 1;
        for (int i = 0; i < size; i++)
            matrix[i, target] += matrix[i, source];
        colMergeCount++;

        newWidth = size - rowMergeCount;
        newHeight = size - colMergeCount;
        smaller = new double[newWidth, newHeight];
        for (int i = 0, j = 0; i < newWidth && j < size; i++, j++)
        {
            for (int k = 0, m = 0; k < newHeight && m < size; k++, m++)
            {
                smaller[i, k] = matrix[j, m];
                Console.Write(matrix[j, m].ToString("00.00") + " ");

                // So merging columns is more expensive because we have to check for it more often while reading.
                if (colsMerged.Contains(m)) m++;
            }

            if (rowsMerged.Contains(j)) j++;
            Console.WriteLine();
        }

        Console.Read();
    }

答案 3 :(得分:0)

在这段代码中,我使用两个1D帮助器列表来计算包含数据的大数组的索引。删除行/列非常便宜,因为我只需要从帮助列表中删除该索引。但当然大数组中的内存仍然存在,即根据您的使用情况,您会有内存泄漏。

public class Matrix
{
    double[] data;
    List<int> cols;
    List<int> rows;

    private int GetIndex(int x,int y)
    {
        return rows[y]+cols[x];
    }

    public double this[int x,int y]
    {
        get{return data[GetIndex(x,y)];}
        set{data[GetIndex(x,y)]=value;} 
    }

    public void DeleteColumn(int x)
    {
        cols.RemoveAt(x);
    }

    public void DeleteRow(int y)
    {
        rows.RemoveAt(y);
    }

    public Matrix(int width,int height)
    {
        cols=new List<int>(Enumerable.Range(0,width));
        rows=new List<int>(Enumerable.Range(0,height).Select(i=>i*width));
        data=new double[width*height];
    }
}

答案 4 :(得分:0)

嗯,对我来说,这看起来像一个简单的二叉树。左侧节点表示行中的下一个值,右侧节点表示该列。

因此,迭代行和列并将它们组合起来应该很容易。

答案 5 :(得分:0)

感谢您的回答。

目前我正在使用此解决方案:

public class NodeMatrix
{

    public NodeMatrix Right { get; set;}
    public NodeMatrix Left { get; set; }
    public NodeMatrix Up { get; set; }
    public NodeMatrix Down { get; set; }
    public int I  { get; set; }
    public int J  { get; set; }
    public double Data { get; set; }

    public NodeMatrix(int I, int J, double Data)
    {
        this.I = I;
        this.J = J;
        this.Data = Data;
    }
}

List<NodeMatrix> list = new List<NodeMatrix>(10000);

然后我正在构建节点之间的连接。之后矩阵就绪了。

这将使用更多内存,但我认为添加行和列,连接行和列等操作会更快。