从Array C ++初始化平衡二进制搜索树

时间:2014-02-09 21:09:52

标签: c++ binary-search-tree

我正在尝试编写一个递归遍历数组的函数,在保持树平衡的同时将值插入树中。假设数组已排序并且我们知道它的大小。我知道我需要做的是从数组的中间开始,将该值插入根,然后取左右两半的中间并将它们插入根的左右节点,依此类推直到数组被填满。递归是我想到的第一件事,我编码的内容是有道理的,但它似乎没有像我想象的那样工作。

我遇到的问题是没有插入第一个和最后一个值,并且我在每个叶子的左侧和右侧获得带有垃圾值的节点,而不是它们是NULL。

节点的结构很简单(由讲师提供):

/* A lightweight structure implementing a general binary tree node */
template <class T>
struct BTNode {
  T       elem;  // element contained in the node
  BTNode *left;  // pointer to the left child (can be NULL)
  BTNode *right; // pointer to the right child (can be NULL)

  // Constructors
  BTNode() { left = right = NULL; }
  BTNode( T elem, BTNode* left = NULL, BTNode* right = NULL ) {
    this->elem = elem;
    this->left = left;
    this->right = right;
  }
  BTNode( const BTNode& src ) {
    this->elem = src.elem;
    this->left = src.left;
    this->right = src.right;
  }

  // Simple tests
  bool is_leaf() const { return (left == NULL && right == NULL); }
};

这是我写的函数:

// ---------------------------------------------------------------------------
// Constructor (from sorted array)
//
template<class T>
BinarySearchTree<T>::BinarySearchTree(T *elements, int n_elements) {

    int high = n_elements-1;
    int low = 0;
    root = new BTNode<T>;
    BSTreeHelper(low, high, elements, BinaryTree<T>::root);
}

构造函数的辅助函数:

template<class T>
void BinarySearchTree<T>::BSTreeHelper(int low, int high, T* elems, BTNode<T>* root) {

    int mid = (low+high)/2;   // to get the middle value
    bool isEqual = (low+1 == high || high-1 == low);

    // if there is a middle value, insert it
    if (!isEqual) {
        BTNode<T>* nodePtrL = new BTNode<T>;
        root->left = nodePtrL;
        BSTreeHelper(low, mid, elems, nodePtrL);

        BTNode<T>* nodePtrR = new BTNode<T>;
        root->right = nodePtrR;
        BSTreeHelper(mid, high, elems, nodePtrR);

        root->elem = elems[mid];

        cout << "Inserted Element = " << root->elem << endl;
    }
}

我似乎无法以任何方式对isEqual进行不同的检查,以便考虑第一个和最后一个元素,而且我真的不确定为什么要使用垃圾值创建额外的节点(值最有可能在数组范围之外)。感谢您的任何帮助,您可以提供。这是一项任务,所以我不想给出答案,但是正确方向的一点非常感谢!

2 个答案:

答案 0 :(得分:1)

什么数组元素是BST的根?中间的一个。
什么数组元素是左子树的根?左子阵列的中间。
什么数组元素将是右子树的根?右子阵的中间。

可以看到递归模式 - 在每次调用中,使当前数组的中间元素范围成为当前子树的根,并在左右子树上应用相同的方法。

这是算法,在伪代码中给出:

TreeNode insertSortedArrayToBST(arr[], start, end):
    if start > end
        return null

    mid := (start + end) / 2
    node := new TreeNode(arr[mid])

    node.left := insertSortedArrayToBST(arr, start, mid - 1)
    node.right := insertSortedArrayToBST(arr, mid + 1, end)

    return node

答案 1 :(得分:1)

您使用递归的想法很好,但如果您为递归函数使用不同的接口,则实现起来要简单得多。

让我们编写一个函数,它接受一个元素数组并返回这些元素的二叉树的根节点。所以这是签名:

template <class T>
BTNode<T> *
treeWithElements(T *elements, size_t count) {

由于此函数将是递归的,因此我们首先考虑基本情况。您可能认为基本情况是count == 1,但事实上基本情况是count == 0。然后没有元素,所以我们需要返回一个空树:

    if (count == 0)
        return NULL;

好的,现在我们知道至少有一个元素。我们将中间元素放在我们即将创建的新节点中作为树的根。这是它的索引:

    size_t middleIndex = count / 2;

要创建节点,我们需要先创建左子节点和右子节点。左子项将包含所有元素,但不包括中间元素:

    BTNode<T> *left = treeWithElements(elements, middleIndex);

(想想看。中间元素的索引也是中间元素之前的元素数。)

我们需要创造一个合适的孩子。它将包含中间元素后面的所有元素:

    BTNode<T> *right = treeWithElements(elements + middleIndex + 1,
        count - (middleIndex + 1));

现在我们可以创建并返回新节点:

    return new BTNode<T>(elements[middleIndex], left, right);
}

总之它非常简单:

template <class T>
BTNode<T> *
treeWithElements(T *elements, size_t count) {
    if (count == 0)
        return NULL;
    size_t middleIndex = count / 2;
    BTNode<T> *left = treeWithElements(elements, middleIndex);
    BTNode<T> *right = treeWithElements(elements + middleIndex + 1,
        count - (middleIndex + 1));
    return new BTNode<T>(elements[middleIndex], left, right);
}

你的包装器类构造函数变成一行:

template<class T>
BinarySearchTree<T>::BinarySearchTree(T *elements, int n_elements) {
    root = treeWithElements(elements, n_elements);
}