Java 图结构的深度复制

Java 图结构的深度复制,java,data-structures,clone,deep-copy,Java,Data Structures,Clone,Deep Copy,我有一个带有节点的graph类,其中每个节点都可以连接到其他节点: public class Node { List<Node> connections; } 公共类节点{ 列出连接; } 我想做一份完整图表的深度拷贝。作为第一次尝试,我尝试制作一个复制构造函数,如: public Node(Node other) { connections = new ArrayList<Node>(); for (Node n : other.connections)

我有一个带有节点的graph类,其中每个节点都可以连接到其他节点:

public class Node {
  List<Node> connections;
}
公共类节点{
列出连接;
}
我想做一份完整图表的深度拷贝。作为第一次尝试,我尝试制作一个复制构造函数,如:

public Node(Node other) {
  connections = new ArrayList<Node>();
  for (Node n : other.connections) { 
    connections.add(new Node(n));
  }
}
公共节点(其他节点){
连接=新的ArrayList();
对于(节点n:other.connections){
添加(新节点(n));
}
}
因此,深度复制图形只会是:

public Graph deepCopy () {
  Graph g = new Graph();
  g.nodes = new ArrayList<Node>();
  for (Node n : nodes) { 
    g.nodes.add(new Node(n));
  }
}
公共图形深度复制(){
图g=新图();
g、 节点=新的ArrayList();
对于(节点n:nodes){
g、 添加(新节点(n));
}
}
但这不起作用,因为这会破坏节点之间的连接关系。我想知道是否有人建议用一种简单的方式来做这件事?谢谢。

是的,可以使用内存
序列化/反序列化

像这样

public static Object copy(Object orig) {
        Object obj = null;
        try {
            // Write the object out to a byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            out.writeObject(orig);
            out.flush();
            out.close();

            // Make an input stream from the byte array and read
            // a copy of the object back in.
            ObjectInputStream in = new ObjectInputStream(
                new ByteArrayInputStream(bos.toByteArray()));
            obj = in.readObject();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        catch(ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
        return obj;
    }
是的,java中的深度复制(不仅仅是java)可以使用内存
序列化/反序列化

像这样

public static Object copy(Object orig) {
        Object obj = null;
        try {
            // Write the object out to a byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            out.writeObject(orig);
            out.flush();
            out.close();

            // Make an input stream from the byte array and read
            // a copy of the object back in.
            ObjectInputStream in = new ObjectInputStream(
                new ByteArrayInputStream(bos.toByteArray()));
            obj = in.readObject();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        catch(ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
        return obj;
    }

问题是您需要复制节点的标识,而不仅仅是它们的值。具体来说,当您复制某个节点时,需要处理它所引用的节点的标识;这意味着复制构造函数或其他纯粹的本地复制机制无法完成这项工作,因为它一次只处理一个节点。我不确定这是否有任何意义,但我已经输入了它,我的退格键不起作用

无论如何,您可以做的是传递一些其他对象,这些对象可以告诉您哪个新节点对应于哪个旧节点。如果你想成为一名花花公子(谁不想呢?),你可以把这称为一种幻想。这可以像地图一样简单。与此完全未经测试的代码一样:

// in Graph
public Graph deepCopy () {
  Graph g = new Graph();
  g.nodes = new ArrayList<Node>();
  Map<Node, Node> isomorphism = new IdentityHashMap<Node, Node>();
  for (Node n : nodes) { 
    g.nodes.add(n.deepCopy(isomorphism));
  }
  return g;
}

// in Node
public Node deepCopy(Map<Node, Node> isomorphism) {
    Node copy = isomorphism.get(this);
    if (copy == null) {
        copy = new Node();
        isomorphism.put(this, copy);
        for (Node connection: connections) {
            copy.connections.add(connection.deepCopy(isomorphism));
        }
    }
    return copy;
}
//在图形中
公共图形复制(){
图g=新图();
g、 节点=新的ArrayList();
映射同构=新的IdentityHashMap();
对于(节点n:nodes){
g、 添加(n.deepCopy(同构));
}
返回g;
}
//在节点中
公共节点deepCopy(映射同构){
节点复制=同构.get(this);
if(copy==null){
复制=新节点();
同构。放(这个,复制);
用于(节点连接:连接){
copy.connections.add(connection.deepCopy(同构));
}
}
返回副本;
}

Sergii提到使用序列化;序列化在遍历对象图时实际上做了一些非常类似的事情

问题是您需要复制节点的标识,而不仅仅是它们的值。具体来说,当您复制某个节点时,需要处理它所引用的节点的标识;这意味着复制构造函数或其他纯粹的本地复制机制无法完成这项工作,因为它一次只处理一个节点。我不确定这是否有任何意义,但我已经输入了它,我的退格键不起作用

无论如何,您可以做的是传递一些其他对象,这些对象可以告诉您哪个新节点对应于哪个旧节点。如果你想成为一名花花公子(谁不想呢?),你可以把这称为一种幻想。这可以像地图一样简单。与此完全未经测试的代码一样:

// in Graph
public Graph deepCopy () {
  Graph g = new Graph();
  g.nodes = new ArrayList<Node>();
  Map<Node, Node> isomorphism = new IdentityHashMap<Node, Node>();
  for (Node n : nodes) { 
    g.nodes.add(n.deepCopy(isomorphism));
  }
  return g;
}

// in Node
public Node deepCopy(Map<Node, Node> isomorphism) {
    Node copy = isomorphism.get(this);
    if (copy == null) {
        copy = new Node();
        isomorphism.put(this, copy);
        for (Node connection: connections) {
            copy.connections.add(connection.deepCopy(isomorphism));
        }
    }
    return copy;
}
//在图形中
公共图形复制(){
图g=新图();
g、 节点=新的ArrayList();
映射同构=新的IdentityHashMap();
对于(节点n:nodes){
g、 添加(n.deepCopy(同构));
}
返回g;
}
//在节点中
公共节点deepCopy(映射同构){
节点复制=同构.get(this);
if(copy==null){
复制=新节点();
同构。放(这个,复制);
用于(节点连接:连接){
copy.connections.add(connection.deepCopy(同构));
}
}
返回副本;
}

Sergii提到使用序列化;序列化在遍历对象图时实际上做了一些非常类似的事情

有点晚了。但我有一个类似的问题,但得到了不同的解决方案。但如果舒尔是防弹的,它就不是了。因此,请随时发表评论,以便我可以学习

我有一种叫做“数字”的类型,因为我没有命名的创意。 每个“数字”类型的对象都有一个内部列表,可以携带“数字”类型的附加对象,每个对象都有一个附加“数字”列表,其中每个。。。等等

基本上,您可以创建类似以下内容的树结构:

我通过在“Numbers”类中使用递归复制构造函数解决了深度复制问题

数字类:

import java.util.ArrayList;

public class Numbers {

    private ArrayList<Numbers> numbers = new ArrayList<>();
    private int number;

    public Numbers(int number) {
        this.number = number;
    }

    public Numbers(Numbers numToCopy) {
        this.number = numToCopy.getNumber();
        ArrayList<Numbers> list = numToCopy.getNumbers();
        for(int i = 0; i < list.size(); i++) {
            Numbers n = new Numbers(list.get(i));
            numbers.add(n);
        }
    }

    public void addNumber(Numbers i) {
        numbers.add(i);
    }

    public ArrayList<Numbers> getNumbers() {
        return numbers;
    }

    public void setNumber(int i) {
        this.number = i;
    }

    public int getNumber() {
        return number;
    }

    public ArrayList<Numbers> getAllNumbers(ArrayList<Numbers> list) {
        int size = numbers.size();
        list.addAll(numbers);
        for(int i = 0; i < size; i++) {
            numbers.get(i).getAllNumbers(list);
        }
        return list;
    }

}
import java.util.ArrayList;

public class NumbersTest {

    public NumbersTest() {

    }

    public static void main(String[] args) {
        Numbers num0 = new Numbers(0);
        Numbers num1 = new Numbers(1);
        Numbers num2 = new Numbers(2);
        Numbers num3 = new Numbers(3);
        Numbers num4 = new Numbers(4);
        Numbers num5 = new Numbers(5);
        Numbers num6 = new Numbers(6);

        num0.addNumber(num1);
        num0.addNumber(num2);

        num1.addNumber(num3);
        num1.addNumber(num4);

        num2.addNumber(num5);
        num2.addNumber(num6);

        num4.addNumber(num6);

        //Deep copy here!
        Numbers numCopy = new Numbers(num0);
        //Change deep down in graph of original
        num0.getNumbers().get(0).getNumbers().get(1).getNumbers().get(0).setNumber(799);
        //Printout of copy to show it was NOT affected by change in original.
        for(Numbers n : numCopy.getAllNumbers(new ArrayList<Numbers>())) {
            System.out.println(n.getNumber());
        }

    }

}
import java.util.ArrayList;
公共课号{
私有ArrayList编号=新ArrayList();
私有整数;
公众号码(整数){
这个数字=数字;
}
公共号码(数字副本){
this.number=numToCopy.getNumber();
ArrayList list=numToCopy.getNumbers();
对于(int i=0;i
用法:

import java.util.ArrayList;

public class Numbers {

    private ArrayList<Numbers> numbers = new ArrayList<>();
    private int number;

    public Numbers(int number) {
        this.number = number;
    }

    public Numbers(Numbers numToCopy) {
        this.number = numToCopy.getNumber();
        ArrayList<Numbers> list = numToCopy.getNumbers();
        for(int i = 0; i < list.size(); i++) {
            Numbers n = new Numbers(list.get(i));
            numbers.add(n);
        }
    }

    public void addNumber(Numbers i) {
        numbers.add(i);
    }

    public ArrayList<Numbers> getNumbers() {
        return numbers;
    }

    public void setNumber(int i) {
        this.number = i;
    }

    public int getNumber() {
        return number;
    }

    public ArrayList<Numbers> getAllNumbers(ArrayList<Numbers> list) {
        int size = numbers.size();
        list.addAll(numbers);
        for(int i = 0; i < size; i++) {
            numbers.get(i).getAllNumbers(list);
        }
        return list;
    }

}
import java.util.ArrayList;

public class NumbersTest {

    public NumbersTest() {

    }

    public static void main(String[] args) {
        Numbers num0 = new Numbers(0);
        Numbers num1 = new Numbers(1);
        Numbers num2 = new Numbers(2);
        Numbers num3 = new Numbers(3);
        Numbers num4 = new Numbers(4);
        Numbers num5 = new Numbers(5);
        Numbers num6 = new Numbers(6);

        num0.addNumber(num1);
        num0.addNumber(num2);

        num1.addNumber(num3);
        num1.addNumber(num4);

        num2.addNumber(num5);
        num2.addNumber(num6);

        num4.addNumber(num6);

        //Deep copy here!
        Numbers numCopy = new Numbers(num0);
        //Change deep down in graph of original
        num0.getNumbers().get(0).getNumbers().get(1).getNumbers().get(0).setNumber(799);
        //Printout of copy to show it was NOT affected by change in original.
        for(Numbers n : numCopy.getAllNumbers(new ArrayList<Numbers>())) {
            System.out.println(n.getNumber());
        }

    }

}
import java.util.ArrayList;
公开课编号测试{
公共号码测试(){
}
公共静态void main(字符串[]args){
数字num0=新数字(0);
数字num1=新数字(1);
数字num2=新数字(2);
数字num3=新数字(3);
数字num4=新数字(4);
数字num5=新数字(5);
编号num6=新编号(6);
num0.addN