有效地将对象矩阵复制到更大的对象矩阵

时间:2010-07-21 18:21:15

标签: c#

我正在编写一个类似四叉树的数据结构,其中包含通用对象T的矩阵。如果四个子节点都包含T的定义矩阵,我将把它们聚合成一个更大的矩阵,然后删除子节点。有没有比循环遍历每个引用并将其复制更有效的方法?我可以复制大块内存吗?


示例:

T[,] _leaf1 = new T[64,64];
T[,] _leaf2 = new T[64,64];
T[,] _leaf3 = new T[64,64];
T[,] _leaf4 = new T[64,64];

// Populate leafs

T[,] _root = new T[128,128];

CopyInto(ref _root, ref _leaf1, 64, 64);
CopyInto(ref _root, ref _leaf2, 0, 64);
CopyInto(ref _root, ref _leaf3, 0, 0);
CopyInto(ref _root, ref _leaf4, 64, 0);

5 个答案:

答案 0 :(得分:1)

如果你可以使结构不可变,你可以省去不必制作大量的副本。 Eric Lippert有一些great posts about immutable structures

编辑: 同样,我不知道它是否会提高您的性能,但这里是一个可能的设计与不可变对象的例子:

abstract class QuadTree<T>
{
    public QuadTree(int width, int height)
    {
        this.Width = width;
        this.Heigth = heigth;
    }

    public int Width { get; private set; }
    public int Height { get; private set; }

    public abstract T Get(int x, int y); 
}

class MatrixQuadTree<T> : QuadTree<T>
{
    private readonly T[,] matrix;

    public QuadTree(T[,] matrix, int width, int heigth)
        : base(width, heigth)
    {
        this.matrix = matrix;
    }

    public override T Get(int x, int y)
    {
       return this.matrix[x, y];
    }
}

class CompositeQuadTree<T> : QuadTree<T>
{
    private readonly QuadTree<T> topLeft;
    private readonly QuadTree<T> topRight;
    private readonly QuadTree<T> bottomLeft;
    private readonly QuadTree<T> bottomRight;

    public CompositeQuadTree(QuadTree<T> topLeft,
        QuadTree<T> topRight, QuadTree<T> bottomLeft,
        QuadTree<T> bottomRight)
        : base(topLeft.Width + topRight.Width, 
            topLeft.Height + bottomLeft.Heigth)
    {
        // TODO: Do proper checks.
        if (this.Width != topLeft.Width + bottomRight.Width)
            throw Exception();

        this.topLeft = topLeft;
        this.topRight = topRight;
        this.bottomLeft = bottomLeft;
        this.bottomRight = bottomRight;
    }

    public override T Get(int x, int y)
    {
        if (x <= this.topLeft.Width)
        {
            if (y <= this.topLeft.Width)
            {
                return this.topLeft.Get(x, y);
            }
            else
            {
                return this.topLeft.Get(x, y + this.topLeft.Heigth);
            }
        }
        else
        {
            if (y <= this.topLeft.Width)
            {
                return this.topRight.Get(x + this.topLeft.Width, y);
            }
            else
            {
                return this.topRight.Get(x + this.topLeft.Width, 
                    y + this.topLeft.Heigth);
            }
        }
    }
}

现在您可以按如下方式使用它:

T[,] _leaf1 = new T[64,64];
T[,] _leaf2 = new T[64,64];
T[,] _leaf3 = new T[64,64];
T[,] _leaf4 = new T[64,64];

// Populate leafs

QuadTree<T> l1 = new MatrixQuadTree<T>(_leaf1,64,64);
QuadTree<T> l2 = new MatrixQuadTree<T>(_leaf2,64,64);
QuadTree<T> l3 = new MatrixQuadTree<T>(_leaf3,64,64);
QuadTree<T> l4 = new MatrixQuadTree<T>(_leaf4,64,64);

// Instead of copying, you can no do this:
QuadTree<T> c = CompositeQuadTree<T>(l1,l2,l3,l4);

// And you can even make composites, of other composites:
QuadTree<T> c2 = CompositeQuadTree<T>(c,c,c,c);

// And you can read a value as follows:
T value = c2[30, 50];

同样,我不知道它是否适合您的情况或是否能提高性能,因为您在获取值时具有一定的间接性。但是,有几种方法可以改善这一点,但这取决于你真正需要做什么。

祝你好运。

答案 1 :(得分:0)

也许我不在这里,但如果你将T限制为引用类型,那么你只会复制引用而不是数据本身。因此,只需在新矩阵中创建对T个对象的新引用,并将其从旧矩阵中删除。以下是约束T的方法。请注意使用whereclass关键字。

public class Foo<T> where T: class
{
}

答案 2 :(得分:0)

或许

System.Buffer.BlockCopy?那将复制大块的记忆。

答案 3 :(得分:0)

如果您不害怕使用不安全的代码并且可以使用引用,则可以使用旧样式指针。首先,您必须使用fixed关键字作为数组。 多维数组将每个维度相互对齐。

答案 4 :(得分:0)

决定将我的评论作为答案。

换句话说:你正在将矩阵的元素复制到其他矩阵中?您可以使用Array.CopyToBuffer.BlockCopy(复制只需几μs)。

此外,如果您修改设计,使其不是array[64],而是array[64*64]并使用模数(%)/ multiply(*)来获取/设置元素,它会更快。不确定你的性能瓶颈在哪里。这取决于您访问矩阵元素的频率与复制频率的频率。

public class Matrix<T>
{
    private int size;
    private T[] elements;

    public Matrix(int size)
    {
        this.size = size;
        this.elements = new T[size];
    }

    T this[int x, int y]
    {
        get
        {
            return elements[x + (y*size)];
        }
        set
        {
            elements[x + (y*size)] = value;
        }
    }

    public void CopyTo(Matrix<T> destination, int x, int y)
    {
        int offset = x + (y*size);
        T[] destinationArray = (T[])destination;
        Buffer.BlockCopy(this.elements, 0, destinationArray, offset, this.elements.Length);
    }

    public static explicit operator T[] (Matrix<T> matrix)
    {
        return matrix.elements;
    }
}

并在代码中:

Matrix<int> leaf = new Matrix<int>(64);
Matrix<int> root = new Matrix<int>(128);
leaf.CopyTo(root, 0, 0);