确定范围是否包含在一组范围内

时间:2017-08-23 19:40:13

标签: c

我在数组中有一组范围。例如(但请注意,我的范围集将大于此值):

static const Section arr[] = {
    {
        .start_addr = 0,
        .length = 100,
    },
    {
        .start_addr = 150,
        .length = 25,   
    },
    {
        .start_addr = 175,
        .length = 25,   
    },

    ...
}

数据不一定要排序,类型都是整数类型。此外,地址永远不会是负数,因此可以是uint32_t

然后,我想通过以下函数查询所有这些范围的并集中是否包含另一个范围:

bool isEncapsulated(uint32_t addr, size_t len){
    // Here I need some sort of algorithm to determine whether 
    // it is fully encapsulated. 
}

我遇到的主要困难是找到一种方法来解释所提供的范围可能落在两个定义范围的边界上的事实。例如。如果start_addr = 170, length = 10落在两个定义范围的边界上。

有没有一种优雅的方法来实现这一目标?

编辑:

Here's图形描述了我正在尝试做的事情。本质上,范围1,2,3是我将在我的数组中定义的。然后,我将请求是否将任何范围A-F封装在其中。所以,D和E是唯一没有的两个。我不只是想要重叠,我希望范围完全包含在预定范围内。

2 个答案:

答案 0 :(得分:2)

如果间隔不多而您只想在不考虑算法的情况下完成工作,只需在O(n)中线性搜索数组。如果列表中的间隔不重叠,请对它们进行排序并使用binary searchO(log n))。如果它们重叠,interval tree是通常选择的数据结构(再次O(log n)),但合并重叠或相邻的区间并进行二分搜索会更简单。

如果你的地址实际上是小整数,并且O(log n)对你来说太慢了(等等,什么?),你可以使用一个填充了所有使用地址的数组来交换{{1}的大量空间你的问题的答案,但你不太可能需要走这条路。

您可以在预处理期间合并相邻的范围(即,事先创建联合),或者您只需要处理这种特殊情况。

答案 1 :(得分:2)

  

我遇到的主要困难是找到一种方法来解释所提供的范围可能超出两个定义范围的边界

情况更糟。范围可能落在许多定义的范围内,并且顺序是询问可能会分割剩余的匹配范围。请考虑以下x中首次找到a范围的情况。之后,x的左侧部分需要与b匹配,右侧部分需要匹配c

Range:      xxxxxxxxxxxx
Def range 1 ___aaaaaa___
Def range 2 bbb_________
Def range 3 _________ccc

一些经过轻微测试的代码。主要想法是在范围addr/len中取左右地址并测试每个部分中的地址。如果它只是一个方面,请继续下一节。否则,缩短addr/len。这可能分为两部分。然后继续下一部分。

typedef struct {
  int start_addr;
  size_t length;
} Section;

// Is point `a` in the section?
// return left:-1, right:1, else 0
static int LeftInRight(intmax_t a, const Section *sec) {
  if (a < sec->start_addr) return -1;
  if (a >= sec->start_addr + (intmax_t) sec->length) return 1;
  return 0;
}

bool isEncapsulated_helper(intmax_t addr, size_t len, const Section *sec, size_t n) {
  for (size_t i = 0; i<n; i++) {
    if (len == 0) return true;
    int LSide =  LeftInRight(addr, &sec[i]);
    if (LSide > 0) continue;  // all of addr/len is to the right of this section
    int RSide =  LeftInRight(addr + (intmax_t) (len - 1), &sec[i]);
    if (RSide < 0) continue;  // all of addr/len is to the left of this section

    if (LSide < 0) {
      // portion of addr/len is to the left of this section
      intmax_t Laddr = addr;
      size_t Llen = (size_t) (sec[i].start_addr - addr);
      if (!isEncapsulated_helper(Laddr, Llen, sec + 1, n-i-1)) {
        return false;
      }
    }
    if (RSide <= 0) return true;
    // portion of addr/len is to the right of this section, continue with that
    intmax_t Raddr = sec[i].start_addr + (intmax_t) sec[i].length;
    size_t Rlen = (size_t) (addr + (intmax_t) len - Raddr);
    addr = Raddr;
    len = Rlen;
  }
  return len == 0;
}

测试代码

static const Section arr[] = { // x
    { .start_addr = 0, .length = 100, }, // x
    { .start_addr = 150, .length = 25, }, // x
    { .start_addr = 175, .length = 25, }, };

#define SECTION_N (sizeof arr/sizeof arr[0])

bool isEncapsulated(int addr, size_t len) {
  return isEncapsulated_helper(addr, len, arr, SECTION_N);
}

int main() {
  printf("%d\n", isEncapsulated(170,10));
}