图结构的深层复制

时间:2010-02-07 15:37:14

标签: c

我在C中有一个图形结构,想要对它进行深层复制(包括节点和边缘)。

结构如下:

struct li_list {
    struct li_node n;
};

struct li_node {
    struct li_node *next, *prev;
};

struct gr_graph {
    struct li_list nodes;
    int nodecount;
};

struct gr_node {
    struct li_node node;
    struct gr_graph *graph;
    int pred_count, succ_count;
    struct li_list pred, succ;
};

struct gr_edge {
    struct li_node succ, pred;
    struct gr_node *from, *to;
    unsigned long marks;
};

这些结构本身并不存在,而是在另一个结构中“继承”,如下所示:

struct ex_node {
    struct gr_node _; // "Superclass"
    int id;
    struct ex_node *union_find_parent;
    ...
}

是否有一种优雅的解决方案可以创建这样的结构的深层副本,包括更新对副本的引用?

注意:嵌套结构的成员不指向它包含的根结构,而是指向它们相关的嵌套结构(例如,ex_node._.pred.n.next指向ex_edge._.pred)。当这些必须更新时,这意味着繁琐的指针算法。

到目前为止我的解决方案是

  1. 记忆所有结构
  2. 遍历所有副本
  3. 为包含引用的所有字段调用一堆宏(由于C中缺少RTTI,我可能不会这样做)
  4. 宏使用
    • offsetof计算根结构的地址
    • 检索复制的等效文件的地址
    • offsetof使指针指向正确的嵌套结构
  5. 有没有更简单的方法呢?我也害怕在添加更多字段时忘记添加宏调用。

4 个答案:

答案 0 :(得分:1)

我认为你本身不能做深度复制,因为指针会有一个分配给指针的内存地址,我能想到深层复制的最好方法就是简单地分配一个新的图形结构并复制数据(而不是指针)并通过malloc新指针从那里构建数据并调整ex_node结构中的指针。那将是一个更彻底的解决方案......

希望这有帮助, 最好的祝福, 汤姆。

答案 1 :(得分:1)

听起来不错。我的0.02美元:

  • 不确定为什么同时需要li_listli_node。此外,您不需要li_node的数据成员吗?
  • 整体结构看起来有点复杂(当然,我不知道你的要求)和C ++风格设计的气味(原谅我,如果我错了)
  • memcpy不是必需的。一个简单的作业就足够了。
  • 使用指针成员为每个结构定义一个函数指针成员,以便您可以执行以下操作:

所以:

struct foo {
   int datum;
   int *p;
   foo_copy pfoo;
};

typedef void (*foo_copy)(const struct foo *src, struct foo *dst);

void foo_cp(const struct foo *src, struct foo *dst)
{ 
    *dst = *src; // copy non-pointer data
    dst->p = malloc(sizeof *dst->p);
    dst->p = *src->p;
}


// somewhere else
struct foo s;
// initalize
struct foo *t = malloc(sizeof *t);  
s.copy(&s, &t);

和嵌套类型调用适当的成员复制方法......

答案 2 :(得分:1)

memcpy所有结构并创建一个排序列表,其中每个条目包含原始结构的地址和结构副本的地址。

现在遍历所有副本。对于所有复制结构中的每个指针变量,搜索已排序列表中的指针并将其替换为其副本的地址。

答案 3 :(得分:0)

是的,使用生成树和装饰器模式有一个优雅的解决方案。

- 首先,构建图的生成树。您可以使用DFS(深度优先搜索) 或者BFS(广度优先搜索)来实现这一点。使用装饰器模式给出 每个访问节点都有一个唯一标识符。

-Next,(或同时)从开始到结束遍历生成树  并通过分配新节点和连接开始构建第二个树  形成生成树的边缘。

- 最后,再次通过生成树,并使用synchronized  标识符,连接新图中剩余的缺失边,以便它们匹配  旧图的连通性。  (例如,如果graph1中的node5具有连接到node7和节点11的边,那么        使用graph2的顺序将其node5连接到node7和11。)