无法将我的头包裹在一个n-ary树上

时间:2013-04-26 06:02:55

标签: java tree n-ary-tree

我正在做一个家庭作业项目,在那里我从一个文件中读取一个连接站列表,并创建一个格式(key = String station,value = ArrayList连接站)的散列图到目前为止一切都很好。

然后,用户可以选择一个本地站,此时我正在尝试创建一个树来代表家中所有可访问的站点。树可以看起来像:

           HomeStation
           /      \
    station1      station2
                /   |     \
        station3 station4 station 5

但我无法理解如何将这些电台添加到除了根及其子节点之外的树上。所以任何人都可以给我一些关于我应该做什么/看什么的指示。

到目前为止

我的TreeNode类:

/**
* TreeNode class 
* Represents a N-ary tree node
* Uses ArrayList to hold the children.
* @author Ásta B. Hansen (11038973)
*
*/
public class TreeNode {
    private String station;
    private TreeNode parent;
    private List<TreeNode> children;

    /**
     * Constructor
     * @param station - the station to be stored in the node
     */
    public TreeNode(String station) {
        this.station = station;
        parent = null;
        children = new ArrayList<TreeNode>(); //Empty list of children  
    }

    /**
     * Sets the station in this node
     * @param station - the station to be stored
     */
    public void setStation(String station) {
        this.station = station;
    }

    /**
     * Returns the station in this node
     * @return station
     */
    public String getStation() {
         return station;
    }

    /**
     * Sets the parent of this node
     * @param parent - the parent node
     */
    public void setParent(TreeNode parent) {
        this.parent = parent;
    }

    /**
     * Returns the parent of this node or null if there is no parent
     * @return parent
     */
    public TreeNode getParent() {
        return parent;
    }

    /**
     * Adds a single child to this node
     * @param newChild - the child node to be added
     */
    public void addChild(TreeNode newChild) {
        children.add(newChild);
        newChild.setParent(this);
    }

    /**
     * Returns a list of the children of this node
     * @return children - the children of the node
     */
    public List<TreeNode> getChildren() {
        return children;
    }

    /**
     * Returns the number of children this node has
     * @return number of children
     */
    public int getNumberOfChildren() {
        return children.size();
    }

    /**
     * Indicates whether this is a leaf node (has no children)
     * @return true if the node has no children 
     */
    public boolean isLeaf() {
        return children.isEmpty();
    }

    /**
     * TODO print preOrder tree
     */
    public void printPreOrder() {

    }

    /**
     * TODO print postOrder tree
     */
    public void printPostOrder() {

    }
}

在Main:

private static void selectHome() {
    if(network != null) {
        System.out.print("Please enter the name of the home station> ");
        homeStation = scan.next();
        if(!network.hasStation(homeStation)) { //if station does not exist
            System.out.println("There is no station by the name " + homeStation + "\n");
            homeStation = null;
        } else {
            //create the tree with homeStation as root
            createTree(homeStation);
        }
    } else {
        System.out.println("You must load a network file before choosing a home station.\n");
    }
}
private static void createTree(String homeStation) {

    root = new TreeNode(homeStation); //create root node with home station
    //TODO Construct the tree

    //get list of connecting stations from network (string[])
    //and add the stations as children to the root node
    for(String stationName : network.getConnections(homeStation)) {
        TreeNode child = new TreeNode(stationName);
        root.addChild(child);
        //then for every child of the tree get connecting stations from network
        //and add those as children of the child. 
        //TODO as long as a station doesn't already exist in the tree.

    }   
}

修改 电台输入文件

Connection: Rame Penlee
Connection: Penlee Rame
Connection: Rame Millbrook
Connection: Millbrook Cawsand
Connection: Cawsand Kingsand
Connection: Kingsand Rame
Connection: Millbrook Treninnow
Connection: Treninnow Millbrook
Connection: Millbrook Antony
Connection: Antony Polbathic
Connection: Polbathic Rame

1 个答案:

答案 0 :(得分:7)

这是一个基本问题(我猜这必须是某种功课),我认为一个简单的递归可以帮助你解决它。

创建一个查找节点的每个子节点的函数,并在每个子节点上调用此函数:

private static void addNodesRecursive(TreeNode node) {
    for(String stationName : network.getConnections(node)) {
        TreeNode child = new TreeNode(stationName);
        node.addChild(child);
        addNodesRecursive(child);
    }   
}

仅当我们制作的图表为DAG时才有效。如果图形中有任何周期(即使是双向边缘),它将失败。

它会失败,因为我们之前尚未存储节点是否已添加到我们的图表中。父母将与孩子相连,反之亦然,他们将作为邻居无限地加入。

你可以做的是:制作一个存储已添加内容的列表。

private static void addNodesRecursive(TreeNode node, List<TreeNode> addedList) {
    for(String stationName : network.getConnections(node)) {
        TreeNode child = new TreeNode(stationName);
        node.addChild(child);
        addedList.add(child);
        addNodesRecursive(child, addedList);
    }   
}

如果新节点不在添加的列表上,则只添加新节点:

private static void addNodesRecursive(TreeNode node, List<String> addedList) {
    for(String stationName : network.getConnections(node)) {
        if (!addedList.contains(stationName)) {
            TreeNode child = new TreeNode(stationName);
            node.addChild(child);
            addedList.add(child);
            addNodesRecursive(child, addedList);
        }
    }   
}

您只需要在根节点上调用它,因此createTree将是:

private static void createTree(String homeStation) {
    root = new TreeNode(homeStation);
    List<String> addedList = new ArrayList<String>();
    addedList.add(homeStation);
    addNodesRecursive(root, addedList);
}

BAM你完成了。调用createTree将从根开始创建树。

P.S。我正在写这个,我没有尝试我的代码,我的Java也有点生疏,所以你可以指望它包含语法错误(就像我已经用小s纠正了我的所有字符串到大写S )。


修改

如果您有任何计划程序的计划,能够自己找出递归问题非常重要。关于如何找出递归的东西的一点帮助。

  1. 有些问题(比如你的)有点像递归的感觉。它们是关于多个方向深入的算法,你只是无法通过一个简单的循环来完成它。或者,当您尝试构建可以包含同一事物的多个实例的内容时,依此类推。但要小心。如果您使用imperative语言进行编程(大多数语言,除declarative之外的ErlangProlog等等,其中递归既是面包也是黄油递归往往相当昂贵。如果你能想到产生相同结果但不是递归的算法,那通常会更便宜。
  2. 如果你认为问题需要递归,那就去吧:尝试找一个递归的构建块。在你的情况下,它是“创建一个节点并添加它的所有子节点对它“。子节点应该包含它们的子节点,因此当您添加子节点时,您在每个节点上调用相同的步骤(步骤是查找并添加其子节点)。
  3. 我们准备好了吗?在处理递归问题时,我常常觉得即使一切都很完美也一定要做点什么。这是因为你没有从头到尾写出algorhythm,而是以一种奇怪的不自然的顺序。在你的情况下,我们还没有准备好。
  4. 为什么它不是无限的?在处理递归时,很容易使函数无限地调用自身,因此stack overflow。我们需要找到函数的边界。在您的情况下,如果节点没有更多子节点,则递归将结束。但是等一下:如果连接是双向的,两个节点将是彼此的子节点,所以每个节点都会有一个子节点!不知何故,我们需要停止将节点添加到树中!我能想到的最简单的解决方案是记住之前添加了哪些节点,并且只添加一个节点如果尚未添加。节点列表是有限的,因此我们最终将耗尽新节点。关键字为,如果。每次递归都应该有一个 if 。并且应该存在递归停止的条件的分支。
  5. 我的algorythm在做什么?当你觉得自己到了某个地方时,停下来,并试着思考你的algorhythm目前在做什么。它将如何开始?有些情况下,您需要在开始递归之前编写几行初始化。在您的情况下,我需要创建根,创建字符串列表,并在调用递归之前将根名称添加到列表中。确保你的algorhythm有一切可以开始。还要确保它在您需要时结束。确保您的条件在正确的地方。试着想一想简单的例子。
  6. 至少我是这样做的(并且在回答这个问题的时候也这样做了:))。