确定跨步阵列是否重叠的算法?

时间:2010-08-23 21:24:04

标签: arrays algorithm

在我正在处理的库中,我们有数据集(可能是其他数据集的子集),这些数据集以三维矩形跨步数组的形式分布在内存中。也就是说,数组A可以下标为A(i,j,k),其中每个索引的范围从零到某个上限,内存中每个元素的位置由下式给出:

A(i,j,k) = A0 + i * A_stride_i + j * A_stride_j + k * A_stride_k

其中A0是基指针,A_stride_i等是尺寸步幅。

现在,因为这些数据集可能是其他数据集的子集,而不是每个数据集占用它们自己的独立malloc内存块,所以它们完全可能重叠(重叠意味着A(i,j,k) < B(m,n,p)并非总是如此如果它们重叠,它们可能相互交错,或者它们可能相互碰撞(其中碰撞意味着A(i,j,k) == B(m,n,p)对于某些指数的六重奏)。

这就是问题所在。对两个数据集(例如,副本)的某些操作仅在数组不相互冲突时有效,但如果它们以交错的非冲突方式重叠则有效。我想为两个数据集添加一个函数,无论两个数据集是否发生冲突。

是否存在以合理有效和直接的方式执行此操作的现有算法?

检查数据集是否重叠相当容易,因此关键问题是:给定这种形式的两个数据集重叠,确定它们是否交错或碰撞的有效算法是什么?

示例:

举一个简单的例子,假设我们的内存位置从0到F(十六进制):

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

为简单起见,我在这里也只考虑2D数组。假设我们有一个大小为2,3(即0 <= i < 20 <= j < 3),其中stride_i = 1stride_j = 4,基地址为2.这将占用(占用的位置由其i,j对表示):

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
      *  *        *  *        *  *

同样,如果我们有另一个相同大小和步幅的数组,从基地址4开始,将如下所示:

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
            o  o        o  o        o  o

在我用于描述问题的术语中,这些数组“重叠”,但它们不会发生碰撞。

限制和假设:

我们可以假设步幅是积极的,并且如果需要,它们正在递增。实际的库中没有任何东西是真的,但重新排列数组定义以达到这一点是相当简单的。

我们可以假设数组不会自交错。图书馆也没有强制执行,但这是一个病态案例,可以单独警告。那就是(假设步幅递增,i范围从零到max_i等等:

  • stride_j >= max_i * stride_i
  • stride_k >= max_j * stride_j

当然,对于不需要这些假设的方法,重点是将数组定义重新排列为规范顺序,这是一些理想的避免工作。

不能假设这两个数组具有相同的大小或步幅。

我认为在施工过程中跟踪事物没有价值 - 在进行测试时,施工中没有信息。此外,“构造”可能只是“考虑这个更大的数组的子集与这个基本指针,这些步幅,以及这些大小。”

最糟糕的案例

svick的回答提醒我,我应该添加一些关于一些典型的“更糟糕”的案例,我希望看到这些案例。最糟糕的情况之一是当我们有一个数组表示一些非常大量的复数值,存储在连续(真实,成对)对中,然后我们有两个子数组分别包含实部和虚部 - 所以,你在数组中有几百万个元素,在数组之间交替。由于这不是一个不太可能发生的情况,因此除了糟糕的表现之外,它应该是可测试的。

1 个答案:

答案 0 :(得分:1)

我认为以下C#程序应该可行。它使用branch and bound method,适用于任意维度的数组。

    using System;
    using System.Collections.Generic;

    namespace SO_strides
    {
        sealed class Dimension
        {
            public int Min { get; private set; }
            public int Max { get; private set; }
            public int Stride { get; private set; }

            private Dimension() { }

            public Dimension(int max, int stride)
            {
                Min = 0;
                Max = max;
                Stride = stride;
            }

            public Dimension[] Halve()
            {
                if (Max == Min)
                    throw new InvalidOperationException();

                int split = Min + (Max - Min) / 2;

                return new Dimension[]
                {
                    new Dimension { Min = Min, Max = split, Stride = Stride },
                    new Dimension { Min = split + 1, Max = Max, Stride = Stride }
                };
            }
        }

        sealed class ArrayPart
        {
            public int BaseAddr { get; private set; }
            public Dimension[] Dimensions { get; private set; }
            public int FirstNonconstantIndex { get; private set; }

            int? min;
            public int Min
            {
                get
                {
                    if (min == null)
                    {
                        int result = BaseAddr;
                        foreach (Dimension dimension in Dimensions)
                            result += dimension.Min * dimension.Stride;
                        min = result;
                    }
                    return min.Value;
                }
            }

            int? max;
            public int Max
            {
                get
                {
                    if (max == null)
                    {
                        int result = BaseAddr;
                        foreach (Dimension dimension in Dimensions)
                            result += dimension.Max * dimension.Stride;
                        max = result;
                    }
                    return max.Value;
                }
            }

            public int Size
            {
                get
                {
                    return Max - Min + 1;
                }
            }

            public ArrayPart(int baseAddr, Dimension[] dimensions)
                : this(baseAddr, dimensions, 0)
            {
                Array.Sort(dimensions, (d1, d2) => d2.Stride - d1.Stride);
            }

            private ArrayPart(int baseAddr, Dimension[] dimensions, int fni)
            {
                BaseAddr = baseAddr;
                Dimensions = dimensions;
                FirstNonconstantIndex = fni;
            }

            public bool CanHalve()
            {
                while (FirstNonconstantIndex < Dimensions.Length
                    && Dimensions[FirstNonconstantIndex].Min == Dimensions[FirstNonconstantIndex].Max)
                    FirstNonconstantIndex++;

                return FirstNonconstantIndex < Dimensions.Length;
            }

            public ArrayPart[] Halve()
            {
                Dimension[][] result = new Dimension[2][];

                Dimension[] halves = Dimensions[FirstNonconstantIndex].Halve();

                for (int i = 0; i < 2; i++)
                {
                    result[i] = (Dimension[])Dimensions.Clone();
                    result[i][FirstNonconstantIndex] = halves[i];
                }

                return new ArrayPart[]
                {
                    new ArrayPart(BaseAddr, result[0], FirstNonconstantIndex),
                    new ArrayPart(BaseAddr, result[1], FirstNonconstantIndex)
                };
            }
        }

        sealed class CandidateSet
        {
            public ArrayPart First { get; private set; }
            public ArrayPart Second { get; private set; }

            public CandidateSet(ArrayPart first, ArrayPart second)
            {
                First = first;
                Second = second;
            }

            public bool Empty
            {
                get
                {
                    return First.Min > Second.Max || Second.Min > First.Max;
                }
            }

            public CandidateSet[] Halve()
            {
                int firstSize = First.Size;
                int secondSize = Second.Size;

                CandidateSet[] result;

                if (firstSize > secondSize && First.CanHalve())
                {
                    ArrayPart[] halves = First.Halve();
                    result = new CandidateSet[]
                    {
                        new CandidateSet(halves[0], Second),
                        new CandidateSet(halves[1], Second)
                    };
                }
                else if (Second.CanHalve())
                {
                    ArrayPart[] halves = Second.Halve();
                    result = new CandidateSet[]
                    {
                        new CandidateSet(First, halves[0]),
                        new CandidateSet(First, halves[1])
                    };
                }
                else
                    throw new InvalidOperationException();

                return result;
            }

            public static bool HasSolution(ArrayPart first, ArrayPart second)
            {
                Stack<CandidateSet> stack = new Stack<CandidateSet>();
                stack.Push(new CandidateSet(first, second));

                bool found = false;

                while (!found && stack.Count > 0)
                {
                    CandidateSet candidate = stack.Pop();
                    if (candidate.First.Size == 1 && candidate.Second.Size == 1)
                        found = true;
                    else
                    {
                        foreach (CandidateSet half in candidate.Halve())
                            if (!half.Empty)
                                stack.Push(half);
                    }
                }

                return found;
            }
        }

        static class Program
        {
            static void Main()
            {
                Console.WriteLine(
                    CandidateSet.HasSolution(
                        new ArrayPart(2, new Dimension[] { new Dimension(1, 1), new Dimension(2, 4) }),
                        new ArrayPart(4, new Dimension[] { new Dimension(1, 1), new Dimension(2, 4) })
                        )
                    );
            }
        }
    }