在java中构建未排序二叉树的最有效方法是啥?

Posted

技术标签:

【中文标题】在java中构建未排序二叉树的最有效方法是啥?【英文标题】:What is the most efficient way to build an unsorted binary tree in java?在java中构建未排序二叉树的最有效方法是什么? 【发布时间】:2015-05-10 01:04:54 【问题描述】:

我需要创建一个未排序的二叉树(一个要求是它是未排序的),其中包含 String 作为其值。我的课程大纲如下所示:

public class Node 

 private String desc;
 private Node leftNode = null;
 private Node rightNode = null;

 public Node(String desc) 
  this.desc = desc;
 

 public String getDesc() 
  return desc;
 

 public Node getLeftNode() 
  return leftNode;
 

 public Node getRightNode() 
  return rightNode;
 

最终,我希望能够将任何与String 描述匹配的节点替换为具有新描述的新节点(包括与旧描述重复的节点)。

所以我的问题是,在创建未排序的二叉树时,处理 Nodes 插入的最佳方法是什么?

我想到了两种方法。第一种是只有两种方法,setLeftNode(Node root, String desc)setRightNode(Node root, String desc),有人可以使用他们选择的Node 作为根调用。如果已经有一个左/右Node,那么它会向下前进,直到它碰到一个没有左Node 的节点。但这可能会通过产生超大高度来引入问题。

我想到的第二种方法是有一个专用的根Node,在这种情况下创建第一个Node,然后按顺序构建新的Nodes。

那么创建未排序二叉树的最佳方法是什么?

【问题讨论】:

从项目列表创建未排序二叉树的最有效方法是获取项目列表并将元素 0 视为根,元素 1 和 2 视为元素 0 的左右节点等。这为您提供了零工作的完美平衡树。但首先这棵树有什么意义呢? @Alex 据我了解,常规二叉树始终未排序。 @Alex 如果您正在寻找Binary Search Tree,那么显然它有自己明确定义的订购方案。对于二叉树,没有最好的方法,这完全取决于您的要求。 【参考方案1】:
public class BinaryTree
    private BinaryTree right;
    private BinaryTree left;
    private String data;        

    public BinaryTree(String s)
        data = s;
        right = null;
        left = null;           
    

    public void setLeft (BinaryTree l) left  = l; 
    public void setRight(BinaryTree r) right = r;         

您的问题表明树应该是平衡的,因此在插入元素时,您应该递归检查树每一侧的节点数:

public int checkTree()
    if(left == null && right == null)
        return 1;
    else if(left == null)
        return 1 + right.checkTree();
    else if(right == null)
        return 1 + left.checkTree();
    else
        return 1 + left.checkTree() + right.checkTree();
    


public void insert(BinaryTree bt)
    if(left == null)
        setLeft(bt);
    else if(right == null)
        setRight(bt);
    else
        if(left.checkTree() <= right.checkTree())
            left.insert(bt);
        else
            right.insert(bt);
        
    

编辑:

public class BinaryTree 
    private BinaryTree right;
    private BinaryTree left;
    private String data;
    private int weight;

    public BinaryTree(String s)
        data = s;
        right = null;
        left = null; 
        weight = 1;
        

    public void setLeft (BinaryTree l) 
        left  = l;
        weight++;
    

    public void setRight(BinaryTree r)
        right = r;
        weight++;
     

    public int getWeight() return weight; 

    public void insert(BinaryTree bt)
        if(left == null)
            setLeft(bt);
        else if(right == null)
            setRight(bt);
        else
            if(left.getWeight() <= right.getWeight())
                left.insert(bt);
                weight++;
            else
                right.insert(bt);
                weight++;
            
        
        
    

【讨论】:

插入时(left == null &amp;&amp; right == null) || left == null)到底需要什么? checkTree() 到底想做什么? 需要(left == null && right == null) || left == null) 是检查子树是否为空,因为我们不能在空值上调用 insert() - 它必须是一棵树。 checkTree() 递归计算节点数,通过比较从左子树和右子树返回的值,我们总是可以选择右分支来调用 insert()。 insert() - 如您所见 - 也是递归的,它将进入一个分支,直到找到不平衡的根源。这样我们的树总是平衡的。 你不认为if(left == null) setLeft(bt); 也可以吗?为什么需要检查两个节点?为了平衡您的树 IMO,这种递归解决方案的开销太大。假设您要插入 10000 个节点。 if(left == null) setLeft(bt); - 你是对的。关于开销,平衡总是很昂贵,但显然还有其他方法可以做到这一点。插入速度可以通过引入额外的属性来提高,该属性将保存子树中的节点数并随着每次插入而更新。通过牺牲一些内存来提高速度。另一方面,一些内存也会被释放,因为我们不再需要 checkTree() 方法了:) 相信我,递归方法在现实世界的项目中大多不是首选:)【参考方案2】:

根据定义,二叉树的最低元素在左侧,最高元素在右侧。但是,如果您真的希望将所有内容都弄乱(排序),则可以调用导致 0 或 1 的 rand 函数,如果 0 则向左移动,如果 1 则随机向右移动。这将导致未排序的树

【讨论】:

A 二叉搜索树 是有序二叉树,不是吗?含义二叉树元素并不总是按左边最小元素/右边最大元素排序。 a binary tree has its lowest elements on the left, and the highest on the right你能详细说明一下吗? IMO 你错了。请不要发布错误的答案。 "二叉搜索树是一棵有根的二叉树,其内部节点每个都存储一个键(以及可选的关联值),每个节点都有两个可区分的子树,通常表示为左和右。树还满足二叉搜索树属性,即每个节点中的键必须大于左子树中存储的所有键,并且小于右子树中的所有键。[1](叶子(最终树的节点)不包含键,也没有结构来区分它们。”,来自*** A Binary TreeBinary Search Tree 不完全相同,并且 OP 要求 Binary Tree【参考方案3】:

最终我希望能够替换任何与字符串匹配的节点 具有新描述的新节点的描述(包括 与旧描述重复)。

为此,您必须搜索整个树:

private Node searchBasedOnValue(String desc, Node currentNode)
  
    Node result = null
    if (currentNode == null)
        return null;
    if (currentNode.getDesc().equals(desc)) 
        return currentNode ;
    if (currentNode.getLeftNode() != null)
        result = searchBasedOnValue(desc,currentNode.getLeftNode());
    if (result == null)
        result = searchBasedOnValue(desc,currentNode.getRightNode());
    return result;

IMO,一个普通的Binary Tree 永远不会被排序,被排序的那个被称为Binary Search Tree。对于插入,您需要以您想要的方式处理。可能您可以在树的左右子节点中交替插入节点,以使其在一定程度上保持平衡。这取决于你如何处理它。

我没有看到常规Binary Tree 的实际用法,因为大多数时候我们使用Binary Search Tree,它在插入、删除和查找方面具有更好的性能(lg(n))。

【讨论】:

【参考方案4】:

如果它是未排序的,为什么要构建一个二叉树呢?如果不进行全扫描就无法搜索它,因此最好将所有内容放在一个数组中,因为无法搜索,访问任何元素都将是 O(n)。

【讨论】:

【参考方案5】:

这是构建未排序二叉树的最快方法,对其形状没有任何限制:

首先你需要一个这样的构造函数:

   public Node(String desc, Node left, Node right) 
       this.desc = desc;
       this.left = left;
       this.right = right;
   

然后像这样构建树:

   Node root = null;
   for (String input: ...) 
      root = new Node(input, root, null);
   

显然,这会为您提供一个不平衡、未排序的树,其搜索需要查看所有节点。但是,如果树是未排序的,那么树不平衡这一事实没有任何区别

一般来说,搜索未排序的树与搜索列表的复杂度相同,而且代码更复杂。

【讨论】:

以上是关于在java中构建未排序二叉树的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

排序:Java实现大顶堆和二叉树的广度优先遍历原理及代码注释详解

找一个Java程序:关于二叉树的建立和排序

二叉树的深度平衡是啥意思?

排序二叉树的遍历( 用递归或非递归的方法都可以)

如何从已排序的流中最好地构建持久二叉树

华中科技大学机试 二叉排序树 Easy *二叉树的构建方式