我有一个B树,我想,给定一个任意的参数键,找出小于或等于参数键的最大数据键,换句话说,我想让它看左边,找出在O(log n)
中应该使用的键。
我已经用C代码修改了implementation of lower_bound。
#define ORDER 3
static int compare(const int a, const int b) { return a > b; }
struct node { unsigned size; int key[ORDER - 1]; };
struct branch { struct node base, *child[ORDER]; };
struct ref { struct node *node; unsigned height, idx; };
struct tree { struct node *node; unsigned height; };
static struct ref lower(const struct tree tree, const int x) {
struct ref lo, found;
found.node = 0;
if(!tree.node) return found;
for(lo.node = tree.node, lo.height = tree.height; ;
lo.node = ((const struct branch *)(const void *)lo.node)->child[lo.idx],
lo.height--) {
unsigned hi = lo.node->size; lo.idx = 0;
if(!hi) continue;
do {
const unsigned mid = (lo.idx + hi) / 2; /* Will not overflow. */
if(compare(x, lo.node->key[mid]) > 0) lo.idx = mid + 1;
else hi = mid;
} while(lo.idx < hi);
if(lo.idx < lo.node->size) { /* Within bounds, record the current. */
found = lo;
if(compare(x, lo.node->key[lo.idx]) > 0) break;
}
if(!lo.height) break;
}
return found;
}
static int tree_lower_or(const struct tree tree,
const int key, const int default_value) {
struct ref ref;
return (ref = lower(tree, key)).node
&& ref.idx < ref.node->size ? ref.node->key[ref.idx] : default_value;
}
#include <stdio.h>
int main(void) {
struct node node[] = { { 2, {1,2} }, { 2, {5, 6} } };
struct branch root = { { 1, {4} }, {node, node+1} };
const struct tree tree = { &root.base, 1 };
int i;
for(i = 0; i < 8; i++)
printf("%d->%d%s", i, tree_lower_or(tree, i, 0), i < 7 ? ", " : "\n");
return 0;
}
这里使用了std::lower_bound中的例子,data = {1,2,4,5,5,6}(注意,我的B树的键是急剧增加的,所以我不能有两个5),它打印出 0-〉1,1-〉1,2-〉2,3-〉4,4-〉4,5-〉5,6-〉6,7-〉0,即x->next x in set or 0
。
这不完全是我想要的。X1 E2 F1 X也不完全是我想要的,但是很接近。
我想要从右边而不是左边得到一个下界,x->last x in set or 0
。
这个函数有名字吗?如何修改上面的lower
来给予这个结果?
2条答案
按热度按时间9jyewag01#
我的实现方法是:
一般来说,你要么关心upper_bound之前的元素,要么关心upper_bound。
0s0u357o2#
按照
upper_bound
的建议,我能够通过保留一个适当更新的返回变量来获得所需的行为,而不需要两次。我发现我有点草率。lower_bound
只是正确地排列,但我发现upper_bound
并不明显。我做的第一件事是设计出一个更好的例子,在这个例子中,什么在范围内,什么在域中是非常明显的。在这个例子中,我认为字母键是域,节点索引是范围,(就像我的问题一样)。
这里,
key
和x
是字母域中的任意元素。对每个node
应用upper_bound
过程,得到范围中的hi
。如果hi.idx
非零,则found.idx = hi.idx - 1
是范围中的一个元素和有效的数据引用。我们沿着树向下,并允许在适当的情况下覆盖它。最后,在tree_left_or
和tree_right_or
中,我们将范围元素found
(它仅仅是不稳定的内部指针索引)变换为键集中有意义的对应字母域键。