以有序的方式遍历两个BST

时间:2015-12-24 11:56:20

标签: algorithm binary-search-tree

这些天我一直在努力实现我的教授要求我们做的一项功能,作为一项挑战,但我无法想到任何可行的方法,所以我在这里看看是否任何人都可以对此有所了解。

这只是关于算法,但我实际上是在C ++中编程,使用根据基本规范编程的BSTree(插入,删除,成员操作)。

问题如下:

假设树的每个节点都包含绝对数字的数字,并且我们有两个不同的BST:一个用于存储负数,另一个用于存储正数。我们可以称他们为negBST和posBST。例如,如果我们输入数字-2 2 5 8 -4 -5 -3 -6,这些将是我们的两棵树:

2                        2
 \                        \
  4                        5
 / \                        \
3   5                        8
     \
      6
Negative BST               Positive BST

目标是打印它们都是有序的,因此,在这种情况下,它会打印:

2 -2 -3 -4 5 -5 -6 8 

现在,面临挑战:实际上是否可以在不使用任何其他辅助动态数据结构(如队列,堆栈,列表等)的情况下执行此操作...?

编辑:       提供的示例可能有点令人困惑,因为树的深度可能会有所不同。

2 个答案:

答案 0 :(得分:3)

一个简单但效率低下的解决方案是将变量n从零迭代到MAX_NUMBER并检查每个迭代和树,如果数字n保存在树中。如果是,请打印(当然否定负面树)。

您还可以并行执行两次深度优先搜索。在每次迭代中,您比较下一个搜索步骤将产生较低数字的树。打印相应树中的数字并进行相应的搜索。

更详细一点:您初始化两个DFS。这为每个树中的一条路径分别指向第一个元素。现在比较元素,选择具有较低元素的树。打印元素(如果需要,使用减号)并在您选择的树中推进DFS。这将为您提供此树中的下一个元素。再次,您比较两个树中的下一个元素,选择较小的元素,等等。

这里有一些类似Javascript / C的伪代码:

// let's assume a DFS and its status is represented by an object
// dfs.next() returns the next number and advances the search
// dfs.peekNext() only returns the next number

var dfsPos = initDFS(posBST);
var dfsNeg = initDFS(negBST);

while (!dfsPos.hasFinished() || !dfsNeg.hasFinished()) {
    if (dfsPos.hasFinished())
        print('-' +dfsNeg.next());
    else if (dfsNeg.hasFinisehd())
        print(dfsPos.next());
    else if (dfsPos.peekNext() < dfsNeg.peekNext()) 
        print(dfsPos.next());
    else
        print('-' +dfsNeg.next());
}

答案 1 :(得分:1)

我将假设negBST和posBST各自包含唯一键。

您可以创建单个BST,例如 commonBST ,而不是尝试同时处理两个单独的BST:s,它们允许非唯一条目。一般来说,这很棘手并且会破坏基本的BST属性,但在这种特殊情况下,它会起作用,如:

  • 对于我们的数字数组(例如:-2 2 5 8 -4 -5 -3 -6),要构建单个 BST commonBST,请仅查看每个数字的绝对值;说KEY = abs(number),并将号码符号与KEY的其他属性相关联,比如说KEY.sign。每个可能的KEY只能存在以下状态:

    • nil(不存在于树中)
    • KEYKEY.keySign=-1 for - )
    • KEYKEY.keySign=+1 for +)
    • KEY,两个标志,KEY.keySign=0
  • 如果我们已经有两棵树(而不是创建两棵树的初始数组),我们只需将negBST添加到posBST即可实现上述的commonBST。

由于negBST和posBST只包含唯一键,因此commonBST键中唯一的退化可能是特定KEY的+和 - 出现。

使用此模式,我们可以创建commonBST(使用您的数字数组作为示例):

For key C:
    C*: C contains both +C and -C (keySign = 0)
    C : C contains only one of +C and -C (get sign from keySign)

Example binary tree for numbers [-2, 2, 5, 8, -4, -5, -3, -6]:

    2*
     \
     5*
   /    \
  4      8
 /      /
3      6

以下swift代码构造了这样一个树

// adapted from "regular" BST in Swift from: 
// http://waynewbishop.com/swift/binary-search-trees/

//generic binary search tree
public class AVLTree {
    var key: Int?
    var keySign: Int? // -1 or 1 for unique entries, 0 if both
    var left: AVLTree?
    var right: AVLTree?

    init() { }

    //add item based on its value
    func addNode(key: Int) {

        //check for the head node
        if (self.key == nil) {
            self.key = abs(key)
            self.keySign = abs(key)/key
            return
        }

        // check for duplicate key
        if (abs(key) == self.key) {
            self.keySign = 0
        }

        //check the left side of the tree
        else if (abs(key) < self.key) {
            if (self.left != nil) {
                left!.addNode(key)
            }
            else {
                //create a new left node
                let leftChild : AVLTree = AVLTree()
                leftChild.key = abs(key)
                leftChild.keySign = abs(key)/key
                self.left = leftChild
            }
        }

        //check the right side of the tree
        else if (abs(key) > self.key) {
            if (self.right != nil) {
                right!.addNode(key)
            }
            else {
                //create a new right node
                let rightChild : AVLTree = AVLTree()
                rightChild.key = abs(key)
                rightChild.keySign = abs(key)/key
                self.right = rightChild
            }
        }
    }
}

let numberList : Array<Int> = [-2, 2, 5, 8, -4, -5, -3, -6]

//create a new BST instance
var root = AVLTree()

//sort each item in the list
for number in numberList {
    root.addNode(number)
}

这使用纯粹的命令式方法,因此您应该能够将其用作您所选语言的详细伪代码。

commonBST只能扩展为常规BST,但只需在展开每个密钥时检查属性keySign

  • 如果keySign=1print(key)
  • 如果keySign=-1print(-key)
  • 如果keySign=0print(-key)&amp; print(key)(或您选择的订单)。

这应该具有任何常规BST的复杂度,O(log n)平均用于插入和查找。