我从编程任务开始。我必须根据图表设计DFA。这是我用于它的数据结构:
typedef struct n{
struct n *next[255]; //pointer to the next state. Value is NULL if no transition for the input character( denoted by their ascii value)
bool start_state;
bool end_state;
}node;
现在,我已准备好基于DFA图形的结构。我需要在几个地方使用这个DFA; DFA将在以下几个地方进行修改。但我希望将未修改的DFA传递给这些不同的功能。一种方法是创建此DFA的副本。这样做最优雅的方式是什么?因此,所有这些都使用NULL值或指向另一个状态的指针进行初始化。
注意: 我希望在被调用函数中创建副本,即我传递DFA,被调用函数创建其副本并对其进行操作。这样,我的原始DFA仍未被阻止。
更多说明:
从DFA的每个节点,我可以有一个有向边连接它与另一个边,如果在输入字母为c
时发生转换,那么state->next[c]
将有一个下一个节点的指针。 next
数组的几个元素可能为NULL。修改NFA意味着添加新节点以及更改当前节点。
答案 0 :(得分:2)
如果你需要在每次调用时都有一个私有副本,并且由于这是一个链接数据结构,我认为没有办法避免复制整个图形(除非对性能执行写入时复制到某些子分支)这是至关重要的,但复杂性很大,错误的可能性也很大。
如果这是c ++,您可以在复制构造函数中完成此操作,但在c中您只需要克隆每个函数。一种方法是克隆整个结构(像Mark建议的那样) - 它非常复杂,因为你需要跟踪图中的周期/后沿(它表现为指向你不想重新分配的先前访问过的节点的指针但重用你的内容已经分配了)。
另一种方式,如果您愿意更改数据结构,则使用数组 - 将所有节点保留在单个节点类型数组中。如果您知道限制,数组应该足够大以容纳所有节点,或者只是根据需要重新分配它以增加,并且每个“指针”都被简单的索引替换。
构建此数组是不同的 - 而不是mallocing一个新节点,使用下一个可用的索引(保持在侧面),或者如果您要动态添加/删除节点,您可以保留队列/堆栈的“免费”索引(在1..N开头填充,并在需要新位置或即将释放旧位置时弹出/推送。
好处是复制速度会快得多,因为所有链接都是相对于数组的实例,你只需复制一块连续的内存(memcpy现在可以正常工作)
另一个好处是使用这种数据结构的性能应优于链接数据,因为内存访问在空间上很接近且易于预取。
答案 1 :(得分:0)
您需要编写一个访问所有节点的递归函数,其中包含一个全局字典,用于跟踪从源图节点到复制的图节点的映射。这个字典基本上是一个将旧指针映射到新指针的表。
这是个主意。我没有编译或调试它......
struct {
node* existing;
node* copy
} dictionary[MAX_NODES] = {0};
node* do_copy(node* existing)
{
node* copy;
int i;
for(i=0;dictionary[i].existing;i++) {
if (dictionary[i].existing == existing) return dictionary[i].copy;
}
copy = (node*)malloc(sizeof(node));
dictionary[i].existing = existing;
dictionary[i].copy = copy;
for(int j=0;j<255 && existing->next[j];j++) {
node* child = do_copy(existing->next[j]);
copy->next[j] = child;
}
copy->end_state = existing->end_state;
copy->start_start = existing->start_state;
return copy;
}