排序一个数组来制作一个有点平衡的二叉搜索树

order an array to make a somewhat-balanced binary search tree

虽然这个问题的目的可能不会有什么不同,但我还是要说明一下。我正在制作一种在图形上执行 Dijkstra 算法的方法。该算法需要一组 U 未访问过的城市。当访问一个城市时,它必须从列表中删除。

所以我想为我的集合 U 使用二叉搜索树,因为它是我能想到的最好的数据结构,它将允许我拥有一大组城市,我可以从中高效地搜索和删除。

城市数组按字母顺序排列,对于索引为 1,2,..n 的数组,cities[0] = Albany NY,cities[n] = Yuma AZ。

我创建了一个我想使用的二叉搜索树,但它不是自平衡的。如果我按原样添加所有元素,它实际上只会创建一个高度为 (n-1) 的链表。

因此,我的问题如下:如果我按顺序添加数组,我该如何排序数组,或者我应该以什么顺序将数组添加到 BST 中,以便生成的 BST 更接近于 log(n)?

我将在创建 BST 时使用以下构造函数

//this constructor initialized a BST with a City array
//a node is created with the City object, and then appended to 
//the tree
BST(City[] cities)
{
    for (int i = 0; i < cities.length; i++)
    {
        BSTNode newNode = new BSTNode(cities[i]);

        append(newNode);
    }

}//end BST(int[]) ----------------------------------------------------------

使用的追加方法是:

//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\
//:::::::::::::::::  APPEND METHODS :::::::::::::::::::::::::::::::::::::| 
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::/
//append (BSTNode) calls append(BSTNode,BSTNode), with the second parameter                                        
//root and first parameter passed from this methods parameter.  
//append finds the correct location for a node and inserts it 
//
//append(BSTNode,BSTNode) adds newNode to the tree at the appropriate location
//current is used in the recursive step
//
//append(City) creates a new node with the City parameter and passes that 
// node as a parameter in append(BSTNode)
public void append(City city)
{
    BSTNode newNode = new BSTNode(city);
    append(newNode);
}//end append(int) --------------------------------------------------------

public void append(BSTNode newNode)
{
    append(newNode, root);
}//end append(BSTNode) ----------------------------------------------------

private void append(BSTNode newNode, BSTNode current)
{
    if (root == null)
    {
        //setup root node for an empty tree
        root = newNode;
        root.setDepth(0);
        size = 1;
    } else
    {
        //add 1 to depth in each level of recursion
        newNode.setDepth(current.getDepth() + 1);

        //if newNode comes first in lexographical order compared to current
        // then place left or go left
        if (newNode.compareTo(current) < 0)
        {
            if (current.getLeft() == null)//if spot is empty
            {
                current.setLeft(newNode);//place node

                size++;
            } else
            {
                append(newNode, current.getLeft());//else recall this method
            }
            //if newNode is after current in lexographical order, then
            //place right or go right   
        } else if (newNode.compareTo(current) > 0)
        {
            if (current.getRight() == null)//if spot is empty
            {
                current.setRight(newNode);//place node

                size++;
            } else
            {
                append(newNode, current.getRight());//else recall method
            }
        } else//if newNode has data that another node already has then
            //print error and do not add
        {
            System.out.println("Attempting to append a duplicate node.\nThe"
                    + "city " + newNode.getData().getName() 
                    + "already is in a node that"
                    + "exists in this BST.\nNo element appended.");
        }
    }//end else*(root != null)
}//end append(BSTNode,BSTNode) ---------------------------------------------

对于您未访问过的城市集,请考虑 HashMap<String, City>HashSet<City>。在任何一种情况下,查找成本都是恒定的(即 O(1)),对于足够大的 n,这比 O(log(n)) 更好。

实现 Dijkstra 算法的一种常用方法是使用按成本排序的节点堆。在 Java 中,这可能由 TreeMap<Double, City> 或一组按成本排序的成本-城市对表示,可能基于 PriorityQueue。在算法的每一步,继续删除 TreeMap.firstEntry(),直到条目的值出现在未访问城市列表中。

条目的密钥为您提供了到达新发现的城市的最低费用。找到新城市后,将所有与它有链接的城市添加到堆中,关键是到达每个城市的总成本。除非您对替代路径感兴趣,否则将已经到达的城市添加到堆中是没有意义的。