具有循环检查的非二叉树实现

时间:2019-03-09 22:26:55

标签: java data-structures tree

我一直在寻找一种满足我的需求但没有找到一个好的非二进制树实现。

我需要一个非二叉树,其中子节点的数目是任意的,并且可以遍历。这棵树是由用户输入构建的,因此我需要进行周期性检查。其他功能包括删除节点(及其子节点),遍历以获取节点的子节点(及其子节点)以及添加子节点(及其他树)。

我在网上发现的实现示例包括使用firstchild-nextsibling方法和到节点的父子链接。 firstchild-nextsibling方法的问题是将树和节点添加到树中。父子方法似乎是合理的,但我还没有找到将整个树添加为子树并具有循环检查的实现。

此类实现的示例:

     A
   /   \
  U     W

然后用户选择创建另一棵树:

  B
 /  \
X    R

,然后将B添加为W的子代。完整的树将是:

    A
  /   \
 U      W
         \
           B
          /  \
         X     R

如果有更好的方法来实现此数据结构,那么我将很高兴听到它,因为我什么也想不了。任何帮助将不胜感激。谢谢!

编辑:我写的一些代码。

public class TreeNode<T> {

private T data;
private TreeNode<T> firstChild;
private TreeNode<T> nextSibling;
private TreeNode<T> parent;
public TreeNode(T data) {
    this.data = data;
}

public boolean isRoot() {
    return this.parent == null;
}
public boolean isaLeaf() {
    return this.firstChild == null;
}

public TreeNode<T> getFirstChild(){
    return firstChild;
}
public void addChild(TreeNode<T> child) {
    child.parent = this;
    if (this.firstChild == null) {
        this.firstChild = child;
    } else {
        child.nextSibling = firstChild;
        firstChild = child;
    }
}

public TreeNode<T> getParent(){
    return parent;
}

public TreeNode<T> getNextSibling() {
    return nextSibling;
}

public T getData() {
    return data;
}

}

编辑2:我的树允许添加类似的节点,但是它不允许创建无限循环。这样的循环的一个示例是将W作为R的子级添加。我当时考虑将每个级别作为链接列表以简化排序,但是我不确定这是否有意义。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

您可以将循环检查添加到addChild方法:

Build system information

error: Multiple commands produce '/Users/tanhaeirad/Project/Rahanj/RezasPortal/portalapp/ios/build/Build/Products/Debug-iphonesimulator/portalapp.app/AntDesign.ttf':
1) Target 'portalapp' (project 'portalapp') has copy command from '/Users/tanhaeirad/Project/Rahanj/RezasPortal/portalapp/node_modules/native-base/Fonts/AntDesign.ttf' to '/Users/tanhaeirad/Project/Rahanj/RezasPortal/portalapp/ios/build/Build/Products/Debug-iphonesimulator/portalapp.app/AntDesign.ttf'
2) Target 'portalapp' (project 'portalapp') has copy command from '/Users/tanhaeirad/Project/Rahanj/RezasPortal/portalapp/node_modules/react-native-vector-icons/Fonts/AntDesign.ttf' to '/Users/tanhaeirad/Project/Rahanj/RezasPortal/portalapp/ios/build/Build/Products/Debug-iphonesimulator/portalapp.app/AntDesign.ttf'

答案 1 :(得分:0)

我假设您的意图是使数据结构成为树,而不是DAG(有向无环图)。这是一些将树与图区分开的属性。

  • 在树中:

    • 没有节点具有多个父节点,
    • (恰好)一个节点是树的根:该根节点没有父节点,并且
    • 对于节点n的每个子c,n == c.parent()
  • 在图形或DAG中,某些节点可能具有多个父节点,并且可能有多个根节点,或者没有根节点。

很显然,就纯数据结构而言,相同的表示类型可以表示树,图或DAG,这取决于将它们组合在一起的方式。因此,为了确保您的数据结构是一棵树,您需要维护上面的属性。这可以通过限制可以执行的转换并在其上放置一些先决条件来完成。以下内容就足够了:

  • 将节点n1添加为节点n2的子节点:

    • pre:n1必须是根节点;即n1.parent == null
    • pre:n2必须是与n1不同的树的一部分;即root(n2)!= n1
    • 操作:设置n1.parent = n2
    • 操作:将n1添加到n2.children
    • post:parent(n1)= n2,这意味着root(n1)== root(n2)
  • 从父节点n2中删除节点n1:

    • pre:n1.parent == n2;即n1不是根
    • pre:n2.children包含n1
    • 操作:将n1.parent设置为null
    • 操作:从p2.children中删除n1
    • post:n1是一个根节点。

正如您所看到的,您唯一需要做的一点棘手的事情是在将n1和n2加到另一个之前,先检查n1和n2是否没有相同的根。可以使用一个简单的递归辅助函数来完成:

  TreeNode root(TreeNode n) {
      return (n.parent == null) ? n : root(n.parent);
  }

然后

  void add(TreeNode n1, Tree node n2) {
      if (root(n1) != n1 || n1 == root(n2)) {
          throw new BadTreeTransformation(...);
      }

如果您限制用户界面,以便所有树形转换都由上述插入和删除操作组成,那么将保留tee不变式。