首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将范围划分为范围的算法,然后找出一个数字属于哪个范围

将范围划分为范围的算法,然后找出一个数字属于哪个范围
EN

Software Engineering用户
提问于 2013-02-20 08:04:10
回答 3查看 43.1K关注 0票数 9

拥有

  • 最小值
  • 最大值
  • 范围数
  • 最小值和最大值之间的值

我试图想出一个或两个方法来计算所提供的值属于哪个范围。

对于min=1,max = 10,范围为1,2、3,4、5,6、7,8、9-10。

另一个方法的行为如下所示:

  • 方法(1)->1-2
  • 方法(2)->1-2
  • 方法(3)->3-4
  • 方法(4)->3-4
  • 方法(5)->5-6
  • 方法(6)->5-6
  • 方法(7)->7-8
  • 方法(8)->7-8
  • 方法(9)->9-10
  • 方法(10)->9-10

这将用于为地图生成图例,其中标记的大小取决于值所属的范围。

我想知道是否有一个很好的算法解决方案。

我处理的数字是整数。

编辑:

另一个例子是:

对于min=1,max = 3,范围为ranges=2的数目

( a) 1-2、3-3

( b) 1-1、2-3

另一个方法的行为如下所示:

a)

  • 方法(1)->1-2
  • 方法(2)->1-2
  • 方法(3)->3-3

或( b)

  • 方法(1)->1-1
  • 方法(2)->2-3
  • 方法(3)->2-3

我不喜欢a)或b)。

EN

回答 3

Software Engineering用户

发布于 2013-03-24 15:20:34

我会这样做:

首先,从数组开始,即范围数的大小,以跟踪每个范围的长度。让我们称其为bucket_sizes[number_of_ranges]

  1. 用尽可能高的均匀长度初始化每个桶的大小:(max-min+1)/number_of_ranges (整数除法)
  2. 然后,找出每个桶中不能均匀匹配的盈余,(max-min+1) % number_of_ranges (整数除法的余数)。
  3. 尽可能均匀地在每个桶之间分配盈余(从索引0开始,在每个桶中添加1,而从剩余中减去1)。如果索引包装到bucket_size数组的末尾,则再次从索引0开始,并继续到剩余值为0)。

既然我们知道了每个桶的大小,就可以生成范围:

代码语言:javascript
运行
复制
for (i=0, k=min; i<number_of_ranges; i++) {
  ranges[i].lo = k;
  ranges[i].hi = k+bucket_sizes[i]-1;
  k += bucket_sizes[i];
}

要找到特定数字的范围,只需迭代ranges数组并匹配ranges[i].lo <= number <= ranges[i].hi所在的范围。

下面是我用来测试它的完整源代码(用C编写):

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct range
{
    int lo;
    int hi;
};

int generate_ranges(int min, int max, int number_of_ranges, struct range ranges[])
{
    int i;
    int bucket_sizes[number_of_ranges];

    int even_length = (max-min+1)/number_of_ranges;
    for(i=0; i<number_of_ranges; ++i)
        bucket_sizes[i] = even_length;

    /* distribute surplus as evenly as possible across buckets */
    int surplus = (max-min+1)%number_of_ranges;
    for(i=0; surplus>0; --surplus, i=(i+1)%number_of_ranges)
        bucket_sizes[i] += 1; 

    int n=0, k=min;
    for(i=0; i<number_of_ranges && k<=max; ++i, ++n){
        ranges[i].lo=k;
        ranges[i].hi=k+bucket_sizes[i]-1;
        k += bucket_sizes[i];
    }
    return n;
}

int number_range_index(int number, int number_of_ranges, const struct range ranges[]) {
    int i;
    for(i=0; i<number_of_ranges; ++i)
        if(number >= ranges[i].lo && number <= ranges[i].hi)
            return i;
    return number_of_ranges;
}


#define MAX_RANGES 50

int main(int argc, char *argv[]) {
    int i;
    struct range ranges[MAX_RANGES];

    if(argc != 5) {
        printf("usage: %s <min> <max> <number_of_ranges> <number>\n", argv[0]);
        return EXIT_FAILURE;
    }

    int min = atoi(argv[1]);
    int max = atoi(argv[2]);
    int number_of_ranges = atoi(argv[3]);
    int number = atoi(argv[4]);

    assert(max > min);
    assert(number >= min && number <= max);
    assert(number_of_ranges > 0);
    assert(number_of_ranges <= MAX_RANGES);

    printf("min=%d max=%d number_of_ranges=%d number=%d\n\n", min, max, number_of_ranges, number);

    int n = generate_ranges(min, max, number_of_ranges, ranges);
    for(i=0; i<number_of_ranges; i++) {
        if(i<n)
            printf("%s[%d-%d]", i>0?",":"", ranges[i].lo, ranges[i].hi);
        else
            printf("%s[]", i>0?",":"");
    }
    printf("\n\n");

    int number_idx = number_range_index(number, n, ranges);
    printf("method(%d)->[%d,%d]\n", number, ranges[number_idx].lo, ranges[number_idx].hi);

    return EXIT_SUCCESS;
}
票数 9
EN

Software Engineering用户

发布于 2013-02-20 10:25:40

n是范围的数目。如果您可以将您的范围划分为相等的子范围,您可以这样做:

代码语言:javascript
运行
复制
length_of_range = (max - min + 1) / n

For i = 1 to n:
start_of_range(i) = length_of_range * (i-1) + min  
end_of_range(i) = start_of_range(i) + length_of_range - 1   

method(number) = (number - min) / length_of_range + 1   // '/' is integer division

如果不能将它们划分为相等的子范围,那么第一个(max - min + 1) % n子范围应该有长度((max - min + 1) / n) + 1,其余的应该有长度(max - min + 1) / n。知道了这一点,你应该能够自己调整上述公式。

票数 2
EN

Software Engineering用户

发布于 2019-07-12 14:43:38

下面是奥斯卡·N的答案的C++11版本:

代码语言:javascript
运行
复制
/** Divides a given range of values into consecutive sub-ranges as evenly as possible.
 * Returns a vector of pairs.  The first member of each pair is the min and the second, the max.
 */
std::vector< std::pair<int, int> > generateSubRanges( int mainRangeMin,
                                                      int mainRangeMax,
                                                      int numberOfSubRanges )
{
   std::vector<std::pair<int, int> > result;
   std::vector<int> bucket_sizes;
   int i;

   //init vectors
   bucket_sizes.reserve( numberOfSubRanges );
   result.reserve( numberOfSubRanges );
   for( i = 0; i < numberOfSubRanges; ++i ){
       bucket_sizes.push_back( 0 );
       result.push_back( {0, 0} );
   }

   int even_length = (mainRangeMax-mainRangeMin+1)/numberOfSubRanges;
   for(i=0; i<numberOfSubRanges; ++i)
       bucket_sizes[i] = even_length;

   /* distribute surplus as evenly as possible across buckets */
   int surplus = (mainRangeMax-mainRangeMin+1)%numberOfSubRanges;
   for(i=0; surplus>0; --surplus, i=(i+1)%numberOfSubRanges)
       bucket_sizes[i] += 1;

   int n=0, k=mainRangeMin;
   for(i=0; i<numberOfSubRanges && k<=mainRangeMax; ++i, ++n){
       result[i] = { k, k+bucket_sizes[i]-1 };
       k += bucket_sizes[i];
   }

   return result;
}
票数 1
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/187680

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档