惰性传播几乎总是包含某种哨兵机制。您必须验证不需要传播当前节点,并且此检查应该简单快捷。因此,有两种可能性:
- 牺牲一点内存以在您的节点中保存一个字段,可以很容易地检查它
- 牺牲一点运行时间,以检查节点是否已传播以及是否必须创建其子节点。
我坚持自己的第一个。检查分段树中的节点是否应具有子节点非常简单(
node->lower_value !=node->upper_value),但是您还必须检查这些子节点是否已经构建(
node->left_child,node->right_child),因此我引入了传播标记
node->propagated:
typedef struct lazy_segment_node{ int lower_value; int upper_value; struct lazy_segment_node * left_child; struct lazy_segment_node * right_child; unsigned char propagated;} lazy_segment_node;初始化
要初始化我们称之为节点
initialize的指针的节点指针(或
NULL)和期望
upper_value/
lower_value:
lazy_segment_node * initialize( lazy_segment_node ** mem, int lower_value, int upper_value){ lazy_segment_node * tmp = NULL; if(mem != NULL) tmp = *mem; if(tmp == NULL) tmp = malloc(sizeof(lazy_segment_node)); if(tmp == NULL) return NULL; tmp->lower_value = lower_value; tmp->upper_value = upper_value; tmp->propagated = 0; tmp->left_child = NULL; tmp->right_child = NULL; if(mem != NULL) *mem = tmp; return tmp;}访问
到目前为止,还没有什么特别的事情。这看起来像其他所有通用节点创建方法。但是,为了创建实际的子节点并设置传播标志,我们可以使用一个函数,该函数将在同一节点上返回一个指针,但是在需要时传播它:
lazy_segment_node * accessErr(lazy_segment_node* node, int * error){ if(node == NULL){ if(error != NULL) *error = 1; return NULL; } if(node->propagated) return node; if(node->upper_value == node->lower_value){ node->propagated = 1; return node; } return node;}如您所见,传播的节点几乎会立即退出该功能。相反,未传播的节点将首先检查它是否实际上应包含子节点,然后在需要时创建它们。
这实际上是惰性评估。直到需要时才创建子节点。注意,
accessErr它还提供了一个附加的错误接口。如果您不需要它,请
access改用:
lazy_segment_node * access(lazy_segment_node* node){ return accessErr(node,NULL);}自由
为了释放这些元素,您可以使用通用节点释放算法:
void free_lazy_segment_tree(lazy_segment_node * root){ if(root == NULL) return; free_lazy_segment_tree(root->left_child); free_lazy_segment_tree(root->right_child); free(root);}完整的例子
下面的示例将使用上述函数基于间隔[1,10]创建延迟评估的分段树。您可以看到,第一次初始化后
test没有子节点。通过使用,
access您实际上生成了那些子节点并可以获取它们的值(如果这些子节点通过分段树的逻辑存在):
码
#include <stdlib.h>#include <stdio.h>typedef struct lazy_segment_node{ int lower_value; int upper_value; unsigned char propagated; struct lazy_segment_node * left_child; struct lazy_segment_node * right_child;} lazy_segment_node;lazy_segment_node * initialize(lazy_segment_node ** mem, int lower_value, int upper_value){ lazy_segment_node * tmp = NULL; if(mem != NULL) tmp = *mem; if(tmp == NULL) tmp = malloc(sizeof(lazy_segment_node)); if(tmp == NULL) return NULL; tmp->lower_value = lower_value; tmp->upper_value = upper_value; tmp->propagated = 0; tmp->left_child = NULL; tmp->right_child = NULL; if(mem != NULL) *mem = tmp; return tmp;}lazy_segment_node * accessErr(lazy_segment_node* node, int * error){ if(node == NULL){ if(error != NULL) *error = 1; return NULL; } if(node->propagated) return node; if(node->upper_value == node->lower_value){ node->propagated = 1; return node; } node->left_child = initialize(NULL,node->lower_value,(node->lower_value + node->upper_value)/2); if(node->left_child == NULL){ if(error != NULL) *error = 2; return NULL; } node->right_child = initialize(NULL,(node->lower_value + node->upper_value)/2 + 1,node->upper_value); if(node->right_child == NULL){ free(node->left_child); if(error != NULL) *error = 3; return NULL; } node->propagated = 1; return node;}lazy_segment_node * access(lazy_segment_node* node){ return accessErr(node,NULL);}void free_lazy_segment_tree(lazy_segment_node * root){ if(root == NULL) return; free_lazy_segment_tree(root->left_child); free_lazy_segment_tree(root->right_child); free(root);}int main(){ lazy_segment_node * test = NULL; initialize(&test,1,10); printf("Lazy evaluation testn"); printf("test->lower_value: %in",test->lower_value); printf("test->upper_value: %in",test->upper_value); printf("nNode not propagatedn"); printf("test->left_child: %pn",test->left_child); printf("test->right_child: %pn",test->right_child); printf("nNode propagated with access:n"); printf("access(test)->left_child: %pn",access(test)->left_child); printf("access(test)->right_child: %pn",access(test)->right_child); printf("nNode propagated with access, but subchilds are not:n"); printf("access(test)->left_child->left_child: %pn",access(test)->left_child->left_child); printf("access(test)->left_child->right_child: %pn",access(test)->left_child->right_child); printf("nCan use access on subchilds:n"); printf("access(test->left_child)->left_child: %pn",access(test->left_child)->left_child); printf("access(test->left_child)->right_child: %pn",access(test->left_child)->right_child); printf("nIt's possible to chain:n"); printf("access(access(access(test)->right_child)->right_child)->lower_value: %in",access(access(access(test)->right_child)->right_child)->lower_value); printf("access(access(access(test)->right_child)->right_child)->upper_value: %in",access(access(access(test)->right_child)->right_child)->upper_value); free_lazy_segment_tree(test); return 0;}结果(ideone)
惰性评估测试test-> lower_value:1test-> upper_value:10节点未传播test-> left_child :(无)test-> right_child :(无)通过访问传播的节点:访问(测试)-> left_child:0x948e020访问(测试)-> right_child:0x948e038节点随访问而传播,但子节点不是:访问(测试)-> left_child-> left_child:(无)访问(测试)-> left_child-> right_child :(无)可以对子孩子使用访问权限:访问(test-> left_child)-> left_child:0x948e050访问(test-> left_child)-> right_child:0x948e068可以链接:access(访问(access(test)-> right_child)-> right_child)->下限值:9access(访问(访问(测试)-> right_child)-> right_child)->上限值:10



