我正在尝试编写一个递归遍历数组的函数,在保持树平衡的同时将值插入树中。假设数组已排序并且我们知道它的大小。我知道我需要做的是从数组的中间开始,将该值插入根,然后取左右两半的中间并将它们插入根的左右节点,依此类推直到数组被填满。递归是我想到的第一件事,我编码的内容是有道理的,但它似乎没有像我想象的那样工作。
我遇到的问题是没有插入第一个和最后一个值,并且我在每个叶子的左侧和右侧获得带有垃圾值的节点,而不是它们是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进行不同的检查,以便考虑第一个和最后一个元素,而且我真的不确定为什么要使用垃圾值创建额外的节点(值最有可能在数组范围之外)。感谢您的任何帮助,您可以提供。这是一项任务,所以我不想给出答案,但是正确方向的一点非常感谢!
答案 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);
}