gpt4 book ai didi

java - 圆图的数据结构与算法

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:31:48 24 4
gpt4 key购买 nike

我需要为 Web 客户端的 Circular Data Graph 定义Data StructureAlgorithm
在服务器端,数据将以 2 列 CSV 格式提供(例如发送方、接收方)。
最终输出将以 JSON 格式呈现并发送到网络请求。
我看过一些 Tree 示例,它们可以帮助处理父子关系。但就我而言,我有一个递归关系 ,即Parent 的孙子也可以用作 Parent;当我陷入无限循环时,这让生活变得有些困难。

数据:

Sender,Receiver
A,B
A,H
B,C
B,D
D,E
E,F
F,G
G,C
H,I
H,J
J,K
K,L
L,M
M,K
L,N
N,O
N,P
P,A
N,Q

客户端可能会这样渲染(我只关心Java结构):
客户端可以请求任何节点,我必须生成整个树并发送响应,即 A、K 或 N。

enter image description here

问题:

  1. 满足此要求的最佳数据结构是什么?为了例如 Tree 之类的还是其他的?
  2. 我应该写自己的阅读逻辑吗数据并设置在 Tree 中,或者是否有任何标准算法那里?
  3. 避免递归的最佳方法是什么?

任何工作示例在这里都会真正有帮助:)

另请参阅下面我的工作解决方案。

最佳答案

我确信您已经找到的关于如何实现树状结构的树示例是正确的。在您的情况下,您会增加复杂性,即递归循环可能存在,因为某些子项将是对其祖先之一的精确对象引用。 (对吗?)

由于这种复杂性,任何试图通过遍历每个节点的子节点来遍历树的进程都将围绕这些递归连接循环,直到发生堆栈溢出。

在这种情况下,您实际上不再是在处理一棵树。在数学上,树被定义为 Graph without cycles .在你的情况下你有 cycles ,因此不是一棵树,而是一棵 circular graph .

我过去处理过这种情况,我认为你可以通过两种方式处理。

  1. 打破循环(在对象级别),返回树。在这些递归连接之一发生的地方,不要放置对祖先的真实对象引用,而是放置一个指示它连接到哪个对象的 stub ,而不是对该项目的the对象引用。

  2. 接受您有一个圆形图,并确保您的代码在遍历该图时可以处理这个问题。确保与图形交互的任何客户端代码都可以检测到它何时处于递归分支中并适本地处理它。

恕我直言,选项 2 不是很有吸引力,因为您可能会发现很难保证约束,而且它经常会导致错误。只要您可以为树中的每个项目分配一个唯一标识符,选项 1 就可以很好地工作,尽管客户仍然需要意识到这种可能性的发生,以便他们可以处理解耦链接并正确表示它(例如在树中查看用户界面)。您仍然想要对圆形图建模,但将使用树在对象级别表示它,因为它简化了代码(和表示)。

选项 1 的完整示例:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class CyclicGraphTest
{
public static void main(String[] args)
{
new CyclicGraphTest().test();
}

public void test()
{
NodeManager manager = new NodeManager();
Node root = manager.processNode("ZZZ");
root.add(manager.processNode("AAA"));
manager.get("AAA").add(manager.processNode("BBB"));
manager.get("AAA").add(manager.processNode("CCC"));
manager.get("AAA").add(manager.processNode("DDD"));
manager.get("DDD").add(manager.processNode("EEE"));
manager.get("EEE").add(manager.processNode("FFF"));
manager.get("FFF").add(manager.processNode("AAA"));
manager.get("AAA").add(manager.processNode("JJJ"));
root.add(manager.processNode("EEE"));
GraphWalker walker = new GraphWalker(manager, root, 1);
System.out.println(walker.printGraph());
}

/**
* Basic Node
*/
public class Node implements Iterable<Node>
{
private String id;
private List<Node> children = new ArrayList<Node>();

public Node(String id) {
this.id = id;
}

public boolean add(Node e) {
return children.add(e);
}

public String getId() {
return id;
}

@Override
public Iterator<Node> iterator() {
return children.iterator();
}
}

/**
* Cyclical Reference
*
*/
public class ReferenceNode extends Node
{
private String refId;

public ReferenceNode(String id, String refId) {
super(id);
this.refId = refId;
}

@Override
public boolean add(Node e) {
throw new UnsupportedOperationException("Cannot add children to a reference");
}

public String getRefId() {
return refId;
}
}

/**
* Keeps track of all our nodes. Handles creating reference nodes for existing
* nodes.
*/
public class NodeManager
{
private Map<String, Node> map = new HashMap<String, Node>();

public Node get(String key) {
return map.get(key);
}

public Node processNode(String id)
{
Node node = null;
if(map.containsKey(id))
{
node = new ReferenceNode(getRefId(id), id);
map.put(node.getId(), node);
}
else
{
node = new Node(id);
map.put(id, node);
}
return node;
}

private String getRefId(String id) {
int i = 0;
String refId = null;
while(map.containsKey(refId = id + "###" + i)) { i++; }
return refId;
}

public Node resolve(ReferenceNode node) {
return map.get(node.getRefId());
}
}

/**
* Walks a tree representing a cyclical graph down to a specified level of recursion
*/
public class GraphWalker
{
private NodeManager manager;
private Node root;
private int maxRecursiveLevel;

public GraphWalker(NodeManager manager, Node root, int recursiveLevel) {
super();
this.manager = manager;
this.root = root;
this.maxRecursiveLevel = recursiveLevel;
}

public String printGraph()
{
return printNode(root, 0, " ").toString();
}

private StringBuilder printNode(Node node, int recursionDepth, String prefix) {
Node resolvedNode = resolveNode(node, recursionDepth);
if(resolvedNode != node) {
recursionDepth ++;
node = resolvedNode;
}
StringBuilder sb = new StringBuilder(node.getId());
int i = 0;
for(Node child : node)
{
if(i != 0) sb.append("\n").append(prefix);
sb.append(" -> ").append(printNode(child, recursionDepth, prefix + " "));
i++;
}
return sb;
}

/**
* Returns a resolved reference to another node for reference nodes when the
* recursion depth is less than the maximum allowed
* @param node
* @param recursionDepth
* @return
*/
private Node resolveNode(Node node, int recursionDepth)
{
return (node instanceof ReferenceNode) && (recursionDepth < maxRecursiveLevel) ?
manager.resolve((ReferenceNode) node) : node;
}
}

}

关于java - 圆图的数据结构与算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10874024/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com