我已经实现了一个基于模板的AVL树,并且我正在努力实现一个有序迭代器,它随每个树一起提供,可以插入和删除元素。 我只会在其长度中包含一些代码 - 如果有必要,请告诉我。
以下基于节点的代码
节点包含左右子指针和对树占用的引用。
T * data;
AVLNode<T> * left;
AVLNode<T> * right;
int height;
int balance;
int & occupancy;
插入和删除以递归方式发生,并引用从父项到&#34的指针;这个&#34;在任何一种情况下都作为参数传递。就二叉搜索树而言,它们的实现是相当标准的。通过用后继节点数据替换要移除的节点的数据并删除后继节点,来移除具有两个子节点的节点。
int insert(T * element, AVLNode<T> * &pfp, int &occupancy);
int remove(T & element, AVLNode<T> * &pfp)
左右旋转使用对父节点的指针的引用。
void leftRotation(AVLNode<T> * &pfp) {
pfp = right;
right = right->left;
pfp->left = this;
}
void rightRotation(AVLNode<T> * &pfp) {
pfp = left;
left = left->right;
pfp->right = this;
}
基于迭代器的代码
迭代器是树的一部分,通过引用或指向树的指针调用方法。例如,给定带有printMyTestObject方法的MyTestObject类,可以编写:
TreeAVL<MyTestObject> myTree;
myTree.iteratorBegin();
while (myTree.iteratorHasNext()) {
(myTree.iteratorNext())->printMyTestObject(&cout);
}
迭代器具有以下方法。
void iteratorBegin();
T * iteratorNext();
int iteratorHasNext();
虽然我最初使用std :: stack,但我觉得它实现的出列功能有限。我创建了自己的单链表,它接受并处理void *作为其数据字段。以下Node方法由其根节点上的AVL Tree&lt; iteratorBegin()和iteratorNext()调用。
void begin(List * const iteratorList) {
AVLNode<T> * targetNode = this;
while (targetNode) {
iteratorList->push(targetNode);
targetNode = targetNode->left;
}
}
T * next(List * const iteratorList) const {
AVLNode<T> * returnNode = (AVLNode<T> *)iteratorList->pop();
AVLNode<T> * loadNode = returnNode->right;
while (loadNode) {
iteratorList->push(loadNode);
loadNode = loadNode->left;
}
return returnNode->data;
}
使用O(log(n))内存并且在连续迭代的平均O(1)时间内操作,这一切都很好用。它允许我通过调用iteratorBegin(),iteratorHasNext()和iteratorNext()来迭代整个树,或者通过调用后两种方法来递增。
问题
删除和插入元素可以沿着用于到达迭代器列表顶部节点的堆栈路径重新组织树。这意味着列表中保存的堆栈路径将不正确。除了完全重新填充列表之外,我怎么能实现迭代器来有效地解释树元素的删除和插入?这对于操作而言相当昂贵。我已经在互联网上进行了广泛的搜索,但我无法找到具体的,有效的实现,特别是没有父指针。
有关插入问题的示例:
- g - - g -
/ \ / \
e i c i
/ \ / \ == insert d ==> / \ / \
b f h j b e h j
/ \ / / \
a c a d f
该列表最初包含&#34; a - &gt; b - &gt; e - &gt;克&#34 ;.我们假设我们称之为iteratorNext()。该列表现在包含&#34; b - &gt; e - &gt;克&#34 ;.插入d后,当前迭代器将吐出 b e f g h i j ,完全跳过c和d。
移除问题非常明显。