我想添加一些精细数量的速度范围并将其保存到数据库中

时间:2010-04-23 05:26:19

标签: algorithm logic

..这里我的问题是我应该检查速度范围是否重叠,如果它们重叠,我应该显示一条消息,说明速度范围不能重叠。

Minimum  Maximum     Rate
1           15        10

16          25        15 

3 个答案:

答案 0 :(得分:1)

将每个速度范围视为连续数字线上的线段。为了找到所有重叠,在每个线段重叠处对数字线进行分区。

首先,将每个范围分成开始和结束点。假设你的范围是:

(5,8) (1,5) (14,17) (3,4) (5,10)

为了清楚起见,我打算给他们分配字母:

A=(5,8) B=(1,5) C=(14,17) D=(3,4) E=(5,10)

好的,现在,让我们将这些范围拆分为离散的起点和终点:

A[start]=5, A[end]=8, B[start]=1, B[end]=5, C[start]=14, C[end]=...等。

按值对这些点进行排序,如果值相等,则起点位于结束点之前,以便得到如下列表:

B[start]=1, D[start]=3, D[end]=4, A[start]=5, E[start]=5, B[end]=5, A[end]=8, ...等。

简单,对吧?

现在,只需遍历已排序的列表,保留当前范围的列表。每次进入[start]点时,请将该范围添加到列表中。每次到[end]点时,请从列表中取出范围。

所以对于上面的列表,你会去:

B[start]=1  add B =>    (B)
D[start]=3  add D =>    (B,D)
D[end]=3    remove D => (B)
A[start]=4  add A =>    (B,A)
E[start]=5  add E =>    (B,A,E)
B[end]=5    remove B => (A,E)
A[end]=8    remove A => (E)
  ... and so on

只要您的列表包含多个元素,那就是重叠。因此,对于任何范围,您都可以确切地确定哪个范围在任何特定点重叠。

假设您使用类似快速排序的算法对正在/结束点进行排序,那将是O(n log n)运行时间,并且检测实际重叠是及时的线性,因此整个算法将在{{1}中运行}。

答案 1 :(得分:0)

如果您对值进行排序:

  • 首先在下限
  • 然后在上限

然后你可以按顺序迭代它们,然后检查下一个范围。重叠范围将在序列中彼此相邻。

在你的例子中:

  • 将1-16与10-15(重叠)进行比较
  • 将10-15与15-25进行比较(可能的重叠,取决于您如何定义重叠)

但是,请注意,此算法仅回答“任何范围重叠”的问题,但它并未提供所有重叠组合。例如,在上面的代码中,1-16和15-25重叠,但是你没有得到这种实现的组合。

如果您需要,则需要更智能的算法。

我在这里发布了一个Visual Studio 2008项目:Subversion Repository for SO2696398

主应用程序代码如下所示:

using System;
using System.Linq;
using LVK.Collections;

namespace SO2696398
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var ranges = new[]
            {
                new Range<int, double>(1, 15, 10),
                new Range<int, double>(16, 25, 15),
                new Range<int, double>(8, 22, 7),
            };
            var slices = ranges.Ordered<int, double>().Slice();

            foreach (var slice in slices)
            {
                if (slice.Data.Length == 1)
                    continue;

                Console.Out.WriteLine("overlap at " + slice.Start
                    + "-" + slice.End + ": "
                    + string.Join(" with ",
                    (from range in slice.Data
                     select range.ToString() 
                     + " [rate=" + range.Data + "]").ToArray()));
            }
        }
    }
}

输出结果为:

overlap at 8-15: 1..15 [rate=10] with 8..22 [rate=7]
overlap at 16-22: 8..22 [rate=7] with 16..25 [rate=15]

希望这会有所帮助。项目的类部分是我在主类库中的一小部分类。如果您更愿意链接到完整库,则可以从Subversion Repository for LVK for .NET下载并编译源代码。这里使用的类来自LVK.Core项目。

答案 2 :(得分:0)

您可以在数据库中轻松实现此业务逻辑,以要求将来的任何应用程序都遵循此约束。

我会将逻辑实现为存储过程(或触发器),如下所示:

CREATE PROCEDURE MyDatabase.spInsertSpeedRanges
    @Min int, 
    @Max int,
    @Rate int
AS

select top 1 * 
from tblSpeedRanges 
where (Minimum between @Min and @Max) or (Maximum between @Min and @Max)

if @@RowCount <> 0
  return -1
else
  insert into tblSpeedRanges (Minimum, Maximum, Rate) values (@Min, @Max, @Rate)

GO

然后在您的应用程序中,如果返回-1,则显示您选择的错误消息。