代码之家  ›  专栏  ›  技术社区  ›  dlras2

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

c#
  •  5
  • dlras2  · 技术社区  · 14 年前

    我正在写一个类似四叉树的数据结构,其中包含一般对象的矩阵 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 回复  |  直到 14 年前
        1
  •  1
  •   Steven    14 年前

    如果您可以使结构不可变,那么您也许可以避免自己需要制作大量的副本。埃里克·利珀特有一些 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];
    

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

    祝你好运。

        2
  •  0
  •   Brian Gideon    14 年前

    也许我离基地很远,但如果你限制 T 若要成为引用类型,则只复制引用,而不复制数据本身。所以只需创建新的引用 T 新矩阵中的对象,并将其从旧矩阵中删除。下面是如何约束 T . 注意使用 where class 关键词。

    public class Foo<T> where T: class
    {
    }
    
        3
  •  0
  •   Ben Voigt    14 年前

    System.Buffer.BlockCopy 也许?这将复制内存块。

        4
  •  0
  •   chriszero    14 年前

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

        5
  •  0
  •   Jaroslav Jandek    14 年前

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

    换句话说,你是在把矩阵的元素复制到其他的矩阵中?你可以使用 Array.CopyTo 或A Buffer.BlockCopy (复制只需要几微秒)。

    另外,如果你修改了你的设计 array[64] 但是 array[64*64] 使用模( % /乘法(乘法) * )要获取/设置元素,它将更快。但不确定性能瓶颈在哪里。这取决于你访问矩阵元素的频率和你复制矩阵元素的频率。

    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);