Java 绘制树状图的递归方法
我必须画一个这样的树状图: 但要大得多。这是一些数据集群表示的一个选项。 所以我坚持用递归的方法来绘制树状图 我确实得到了绘制方法应该是这样的原则Java 绘制树状图的递归方法,java,recursion,dendrogram,Java,Recursion,Dendrogram,我必须画一个这样的树状图: 但要大得多。这是一些数据集群表示的一个选项。 所以我坚持用递归的方法来绘制树状图 我确实得到了绘制方法应该是这样的原则 draw(cluster){ if(clusters.hasChildren()){ draw(cluster.child1) draw(cluster.child2) } //draw actual cluster here } 但我在实现它时遇到了很大困难 我目
draw(cluster){
if(clusters.hasChildren()){
draw(cluster.child1)
draw(cluster.child2)
}
//draw actual cluster here
}
但我在实现它时遇到了很大困难
我目前的方法是这样的
drawCluster(cluster, startX, startY){
if(cluster.hasChildren()){
drawCluster, cluster.child1(), cluster.child1().getDepth * 30, height - cluster.child2.getWidth * 20)
drawCluster, cluster.child2(), cluster.child2().getDepth * 30, height - 20)
}
if cluster.getDepth() == 0 )
drawLine(500 - 30), height, 500)
else
drawLine(500 - (width * 30), height, 500);
}
我用来画的空间是500px,宽度和高度的总和是
现在我只为每个簇画一条线,只是为了得到正确的距离。
每次我从500px减去簇深度乘以20开始画一条线,直到第500个像素
此外,高度应为最大高度。例如,在绘图时,假设参数中高度为(1,2)的簇为40。等等
但这并不奏效。基本上,每次调用draw方法时,我都会被困在如何更改值的问题上。除了行的x起点和y起点之外,我还需要传递更多的变量吗
任何帮助都将不胜感激,因为我还有最后期限要赶
提前感谢。因为您不能提供任何特定的数据结构,所以我只能提供伪代码。最重要的部分似乎是自下而上构建树,在构建较高层级时,考虑较低层级的计算宽度
func drawCluster(node:Node, depth:int, top:int) -> int:
if node has children:
next_top = top
for child in node.children:
drawLine(depth, top, depth + 1, next_top)
next_top = drawCluster(child, depth + 1, next_top)
return next_top
else:
drawLabel(node.label, depth, top)
return top + text_height
显然,我无法测试这个,但我曾经为一个图形布局算法做过类似的测试,所以我认为这应该可以工作,除非我误解了你的问题。既然你不能提供任何特定的数据结构,我只能给出伪代码。最重要的部分似乎是自下而上构建树,在构建较高层级时,考虑较低层级的计算宽度
func drawCluster(node:Node, depth:int, top:int) -> int:
if node has children:
next_top = top
for child in node.children:
drawLine(depth, top, depth + 1, next_top)
next_top = drawCluster(child, depth + 1, next_top)
return next_top
else:
drawLabel(node.label, depth, top)
return top + text_height
显然,我不能测试这个,但我曾经为一个图形布局算法做过类似的事情,所以我认为这应该是可行的,除非我误解了你的问题。递归地画一个完全像这样的树状图实际上有点棘手 叶节点无法“知道”其y位置。此外,没有节点“直接”知道必须在哪里绘制,以及如何绘制将其连接到其子节点的线:在绘制所有叶子(或每个节点的子节点)之前,所有这些信息都不可用 我认为迭代解决方案可能更容易、更灵活。然而,这里有一个使用递归方法的实现。请注意,这是一个非常简单的实现,它(例如)假设树状图的数据结构是一个二叉树,但这应该与您发布的示例一致 顺便说一句:它填满了可用的空间,我强烈建议避免“魔法常数”和关于节点或绘图区域像素大小的假设,如
绘图线(500-(宽度*30),高度,500)
。即使您不想根据树的大小和叶节点的数量来计算这些,您也应该至少为其引入变量,以便以后可以更轻松地进行更改
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DendrogramPaintTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DendrogramPaintPanel panel = new DendrogramPaintPanel();
f.getContentPane().add(panel);
f.setSize(1000,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class Node<T>
{
private final T contents;
private final List<Node<T>> children;
Node(T contents)
{
this.contents = contents;
this.children = Collections.emptyList();
}
Node(Node<T> child0, Node<T> child1)
{
this.contents = null;
List<Node<T>> list = new ArrayList<Node<T>>();
list.add(child0);
list.add(child1);
this.children = Collections.unmodifiableList(list);
}
public T getContents()
{
return contents;
}
public List<Node<T>> getChildren()
{
return Collections.unmodifiableList(children);
}
}
class DendrogramPaintPanel extends JPanel
{
private static <T> Node<T> create(T contents)
{
return new Node<T>(contents);
}
private static <T> Node<T> create(Node<T> child0, Node<T> child1)
{
return new Node<T>(child0, child1);
}
private Node<String> root;
private int leaves;
private int levels;
private int heightPerLeaf;
private int widthPerLevel;
private int currentY;
private final int margin = 25;
DendrogramPaintPanel()
{
root =
create(
create(
create("10"),
create(
create("9"),
create(
create("8"),
create("7")
)
)
),
create(
create(
create("6"),
create("5")
),
create(
create("4"),
create(
create("3"),
create(
create("2"),
create("1")
)
)
)
)
);
}
private static <T> int countLeaves(Node<T> node)
{
List<Node<T>> children = node.getChildren();
if (children.size() == 0)
{
return 1;
}
Node<T> child0 = children.get(0);
Node<T> child1 = children.get(1);
return countLeaves(child0) + countLeaves(child1);
}
private static <T> int countLevels(Node<T> node)
{
List<Node<T>> children = node.getChildren();
if (children.size() == 0)
{
return 1;
}
Node<T> child0 = children.get(0);
Node<T> child1 = children.get(1);
return 1+Math.max(countLevels(child0), countLevels(child1));
}
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
leaves = countLeaves(root);
levels = countLevels(root);
heightPerLeaf = (getHeight() - margin - margin) / leaves;
widthPerLevel = (getWidth() - margin - margin)/ levels;
currentY = 0;
g.translate(margin, margin);
draw(g, root, 0);
}
private <T> Point draw(Graphics g, Node<T> node, int y)
{
List<Node<T>> children = node.getChildren();
if (children.size() == 0)
{
int x = getWidth() - widthPerLevel - 2 * margin;
g.drawString(String.valueOf(node.getContents()), x+8, currentY+8);
int resultX = x;
int resultY = currentY;
currentY += heightPerLeaf;
return new Point(resultX, resultY);
}
if (children.size() >= 2)
{
Node<T> child0 = children.get(0);
Node<T> child1 = children.get(1);
Point p0 = draw(g, child0, y);
Point p1 = draw(g, child1, y+heightPerLeaf);
g.fillRect(p0.x-2, p0.y-2, 4, 4);
g.fillRect(p1.x-2, p1.y-2, 4, 4);
int dx = widthPerLevel;
int vx = Math.min(p0.x-dx, p1.x-dx);
g.drawLine(vx, p0.y, p0.x, p0.y);
g.drawLine(vx, p1.y, p1.x, p1.y);
g.drawLine(vx, p0.y, vx, p1.y);
Point p = new Point(vx, p0.y+(p1.y - p0.y)/2);
return p;
}
// Should never happen
return new Point();
}
}
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.Point;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.List;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
公共类树状图测试
{
公共静态void main(字符串[]args)
{
SwingUtilities.invokeLater(新的Runnable()
{
@凌驾
公开募捐
{
createAndShowGUI();
}
});
}
私有静态void createAndShowGUI()
{
JFrame f=新的JFrame();
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
树状图PaintPanel panel=新树状图PaintPanel();
f、 getContentPane().add(面板);
f、 设置大小(1000800);
f、 setLocationRelativeTo(空);
f、 setVisible(真);
}
}
类节点
{
私人最终考试内容;
私人最终名单儿童;
节点(T内容)
{
this.contents=目录;
this.children=Collections.emptyList();
}
节点(节点child0、节点child1)
{
this.contents=null;
列表=新的ArrayList();
列表。添加(0);
添加(child1);
this.children=Collections.unmodifiableList(列表);
}
公共T getContents()
{
返回内容;
}
公共列表getChildren()
{
返回集合。不可修改列表(子项);
}
}
类树状图PaintPanel扩展了JPanel
{
私有静态节点创建(T内容)
{
返回新节点(内容);
}
私有静态节点创建(节点child0,节点child1)
{
返回新节点(child0,child1);
}
私有节点根;
私密的叶子;
私人智力水平;
私人海特佩利夫酒店;
每级私有整数;
私营企业;
私人最终整数保证金=25;
树状图面板()
{
根=
创造(
创造(
创建(“10”),
创造(
创建(“9”),
创造(
创建(“8”),
创建(“7”)
)
)
),
创造(
创造(
创建(“6”),
创建(“5”)
),
创造(
创建(“4”),
创造(
创建(“3”),
创造(
创建(“2”),
创建(“1”)
)
)