层次图算法改造

hhw55512468 2014-04-23 10:19:27
一个练习题,想了很久头晕了,来请教高人们指点。。
是这样,本来的图形是以下形状(原图),代码已经有了,下面附上。



想改造为:最下面一层的节点不要横着放,改为竖着放,这样一来数据多的时候就不会显得一行占太多空间(效果图)。。请高人点拨。。

1、 TreeGraphGenerator
package yfzx.ex01;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class TreeGraphGenerator {
public static void main(String[] a){
TreeGraphGenerator gen=new TreeGraphGenerator();
gen.setDataProvider(new DataProvider(){
String[][] data={
{"000000","国家总局","ROOT"},
{"000012","首都机场办事处","000000"},
{"200000","上海局","000000"},
{"200012","长虹机场办事处","200000"},
{"350000","福建局","000000"},
{"350100","福州局","350000"},
{"350102","马尾办事处","350100"},
{"350112","长乐机场办事处","350100"},
{"352100","宁德局","350000"},
{"352107","三都澳港口","352100"},
{"360000","厦门局","000000"},
{"360011","长崎机场","360000"},
{"362000","漳州局","360000"},
};

public List<Object> getSubNodeData(Object parent) {
List<Object> result=new ArrayList<Object>();
String[] cast=(String[])parent;
String parentId=cast[0];
for(String[] row : data){
if(row[2].equals(parentId)){
result.add(row);
}
}
return result;
}

public List<Object> getTopNodeData() {
return getSubNodeData(new String[]{"ROOT","虚拟根节点",""});
}});
String result= gen.generateHtml();
try {
FileWriter fw=new FileWriter("e:/test_tree.html");
fw.write(result);
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public String generateHtml() {
Graph all=new Graph();
for(Object top:dataProvider.getTopNodeData()){
Graph g=new Graph();
g.setDataProvider(dataProvider);
g.setData(top);
g.buildGraph();
all.combine(g);
}

StringBuilder sb=new StringBuilder();
sb.append("<div style='font-size:9pt'>\r\n");
//划横线
for(Line n:all.getVLines()){
if(n.getLen()>0){
sb.append("<div style='position:absolute;border-top:1px solid gray;" +
"left:"+n.getX()+"px;" +
"top:"+n.getY()+"px;" +
"width:"+n.getLen()+"px;'></div>\r\n");
}
}
//划竖线
for(Line n:all.getHLines()){
if(n.getLen()>0){
sb.append("<div style='position:absolute;border-left:1px solid gray;" +
"left:"+n.getX()+"px;" +
"top:"+n.getY()+"px;" +
"height:"+n.getLen()+"px;'></div>\r\n");
}
}
//画节点
for(Node n:all.getNodes()){
String[] row=(String[]) n.getData();
sb.append("<div style='position:absolute;border:1px solid gray;" +
"width:"+Graph.WIDTH_NODE+"px;height:"+Graph.HEIGHT_NODE+"px;" +
"left:"+n.getX()+"px;" +
"top:"+n.getY()+"px;'>" +
row[1]+"<br/>("+row[0]+")"+
"</div>\r\n");
}
sb.append("</div>");
return sb.toString();
}
private DataProvider dataProvider;
public void setDataProvider(DataProvider dataProvider) {
this.dataProvider=dataProvider;
}
}
2、Graph (画图形)
package yfzx.ex01;

import java.util.ArrayList;
import java.util.List;

public class Graph {
public static int HEIGHT_NODE=40; //节点参数
public static int WIDTH_NODE=120;
public static int PADDING_HORIZONTAL=20;
public static int PADDING_VERTICAL=20;
private Object topNodedata;
private DataProvider dataProvider;
private List<Node> nodes=new ArrayList<Node>(); //节点
private List<Line> vLines=new ArrayList<Line>(); //横线
private List<Line> hLines=new ArrayList<Line>(); //竖线
private List<int[]> scopes=new ArrayList<int[]>();//辅助信息,每行最做和最右的节点位置,如果这行没有节点则为null
public void setDataProvider(DataProvider dataProvider) {
this.dataProvider=dataProvider;
}
public void setData(Object data) {
this.topNodedata=data;
}
/**
* 构建图形
*/
public void buildGraph() {
List<Object> subs=dataProvider.getSubNodeData(topNodedata);
if(subs==null||subs.size()==0){
//仅有一个节点。
nodes.add(new Node(0,0,topNodedata));
scopes.add(new int[]{0,0});
}else{
//深度优先后续遍历节点。
int minX=Integer.MAX_VALUE;
int maxX=Integer.MIN_VALUE;
for(Object sub:subs){
Graph subG=new Graph();
subG.setDataProvider(dataProvider);
subG.setData(sub);
subG.buildGraph();
subG.moveToSub();
int topNodeX=combine(subG);
if(minX>topNodeX){minX=topNodeX;}
if(maxX<topNodeX){maxX=topNodeX;}
//补充所有竖线
Line horLine=new Line(topNodeX+WIDTH_NODE/2,HEIGHT_NODE+PADDING_VERTICAL/2,PADDING_VERTICAL/2);
hLines.add(horLine);

}
//补充横线和中间的竖线。
Line horLine=new Line((minX+maxX+WIDTH_NODE)/2,HEIGHT_NODE,PADDING_VERTICAL/2);
hLines.add(horLine);
Line verLine=new Line(minX+WIDTH_NODE/2,HEIGHT_NODE+PADDING_VERTICAL/2,maxX-minX);
vLines.add(verLine);
//并确定中间节点的位置。
int nodex=(minX+maxX)/2;
nodes.add(new Node(nodex,0,topNodedata));
scopes.set(0,new int[]{nodex,nodex});
}
}
/**
* 把所有节点下移一层,以便合并后,并在上一层添加节点
*/
private void moveToSub() {
for(Node n:nodes){
n.setY(n.getY()+HEIGHT_NODE+PADDING_VERTICAL);
}
for(Line n:vLines){
n.setY(n.getY()+HEIGHT_NODE+PADDING_VERTICAL);
}
for(Line n:hLines){
n.setY(n.getY()+HEIGHT_NODE+PADDING_VERTICAL);
}
this.scopes.add(0,null);
}
/**
* 把图形g的内容整合到本图形中来。
* 返回顶级节点的横坐标,
* 以便如果后续还要组合其他节点的时候定位
* @param g
* @return
*/
public int combine(Graph g) {
//首先判断每行的宽度,看看以哪个偏移量为准
int offset=0;
for(int i=0;i<scopes.size();i++){
if(i>=g.scopes.size())break;
if(scopes.get(i)==null||g.scopes.get(i)==null){
continue;
}
int thisLineOffset=scopes.get(i)[1]+WIDTH_NODE+PADDING_HORIZONTAL-g.scopes.get(i)[0];
if(offset<thisLineOffset){
offset=thisLineOffset;
}
}
//g 的所有线偏移量
for(Node n:g.nodes){
nodes.add(new Node(n.getX()+offset,n.getY(),n.getData()));
}
for(Line n:g.vLines){
vLines.add(new Line(n.getX()+offset,n.getY(),n.getLen()));
}
for(Line n:g.hLines){
hLines.add(new Line(n.getX()+offset,n.getY(),n.getLen()));
}
//判断每一行的最左的节点和最右的节点,并重新计算合并过的图形,最左节点和最右节点
//因为两个图可能高度并不一致,所以需要判断其中一张图可能没有数据或为空的现象。
for(int i=0;i<scopes.size()||i<g.scopes.size();i++){
if(scopes.size()<i+1){
if(g.scopes.get(i)==null){
scopes.add(null);
}else{
scopes.add(new int[]{g.scopes.get(i)[0]+offset,g.scopes.get(i)[1]+offset});
}
}else if(scopes.get(i)==null){
if(g.scopes.get(i)==null){
continue;
}
scopes.set(i,new int[]{g.scopes.get(i)[0]+offset,g.scopes.get(i)[1]+offset});
}else{
if(g.scopes.size()<i+1){
continue;
}
if(g.scopes.get(i)==null){
continue;
}
scopes.get(i)[1]=g.scopes.get(i)[1]+offset;
}
}
return offset+g.nodes.get(g.nodes.size()-1).getX();
}
public List<Node> getNodes() {
return nodes;
}
public void setNodes(List<Node> nodes) {
this.nodes = nodes;
}
public List<Line> getVLines() {
return vLines;
}
public void setVLines(List<Line> lines) {
vLines = lines;
}
public List<Line> getHLines() {
return hLines;
}
public void setHLines(List<Line> lines) {
hLines = lines;
}

}
3、辅助类Line (线)
package yfzx.ex01;

public class Line {
private int x;
private int y;
private int len;
public Line(){}
public Line(int x, int y,int len) {
this.x=x;
this.y=y;
this.len=len;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getLen() {
return len;
}
public void setLen(int len) {
this.len = len;
}
}
4、辅助类Node (节点)
package yfzx.ex01;

public class Node {
private int x;
private int y;
private Object data;
public Node(){}
public Node(int x, int y,Object data) {
this.x=x;
this.y=y;
this.data=data;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
5、辅助类 DataProvider (用来获取节点信息)
package yfzx.ex01;

import java.util.List;

public interface DataProvider {
public List<Object> getTopNodeData();
public List<Object> getSubNodeData(Object parent);
}
...全文
272 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
yyfhz 2014-04-24
  • 打赏
  • 举报
回复
引用 7 楼 hhw55512468 的回复:
[quote=引用 6 楼 yyfhz 的回复:] 原图中的福州局 到 马尾办事处、长乐机场办事处之间的层次关系在新图中丢失,所以不是同一棵树
那只是示意图 那个节点只是忘记填上去了[/quote] 那么正确的图是怎么样子的呢?
hhw55512468 2014-04-24
  • 打赏
  • 举报
回复
引用 9 楼 yyfhz 的回复:
[quote=引用 7 楼 hhw55512468 的回复:]
[quote=引用 6 楼 yyfhz 的回复:]
原图中的福州局 到 马尾办事处、长乐机场办事处之间的层次关系在新图中丢失,所以不是同一棵树


那只是示意图 那个节点只是忘记填上去了[/quote]
那么正确的图是怎么样子的呢?[/quote]

不好意思 那图的确是有问题 太匆忙了

yyfhz 2014-04-23
  • 打赏
  • 举报
回复
原图中的福州局 到 马尾办事处、长乐机场办事处之间的层次关系在新图中丢失,所以不是同一棵树
Inhibitory 2014-04-23
  • 打赏
  • 举报
回复
那就层次遍历树,叶子节点就竖着显示。
hhw55512468 2014-04-23
  • 打赏
  • 举报
回复
引用 2 楼 huxiweng 的回复:
画树的时候改变下结构。 你的竖着的那个有点规律,35开头福建的,350左边,352右边
这个数字是自己定的 没关系的
hhw55512468 2014-04-23
  • 打赏
  • 举报
回复
引用 1 楼 Inhibitory 的回复:
你给出的图已经改变了树的结构,他们不是同一棵树
是同一颗 只是叶子节点横排改为竖排了而已
teemai 2014-04-23
  • 打赏
  • 举报
回复
画树的时候改变下结构。 你的竖着的那个有点规律,35开头福建的,350左边,352右边
Inhibitory 2014-04-23
  • 打赏
  • 举报
回复
你给出的图已经改变了树的结构,他们不是同一棵树
hhw55512468 2014-04-23
  • 打赏
  • 举报
回复
引用 5 楼 Inhibitory 的回复:
那就层次遍历树,叶子节点就竖着显示。
没错,,只是方法实现没那么简单。。。
hhw55512468 2014-04-23
  • 打赏
  • 举报
回复
引用 6 楼 yyfhz 的回复:
原图中的福州局 到 马尾办事处、长乐机场办事处之间的层次关系在新图中丢失,所以不是同一棵树
那只是示意图 那个节点只是忘记填上去了

50,528

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧