Fix avl tree destructor
This commit is contained in:
parent
7d8cf66b27
commit
14cb588948
1 changed files with 141 additions and 133 deletions
|
|
@ -61,10 +61,143 @@ namespace tp {
|
||||||
inline void updateTreeCacheCallBack() { key.updateTreeCacheCallBack(*this); }
|
inline void updateTreeCacheCallBack() { key.updateTreeCacheCallBack(*this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
public:
|
||||||
Node* mRoot = nullptr;
|
AvlTree() { MODULE_SANITY_CHECK(gModuleContainers) }
|
||||||
ualni mSize = 0;
|
~AvlTree() { removeAll(); }
|
||||||
Allocator mAlloc;
|
|
||||||
|
[[nodiscard]] ualni size() const { return mSize; }
|
||||||
|
|
||||||
|
Node* head() const { return this->mRoot; }
|
||||||
|
|
||||||
|
void insert(KeyArg key, DataArg data) {
|
||||||
|
mRoot = insertUtil(mRoot, key, data);
|
||||||
|
mRoot->mParent = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(KeyArg key) {
|
||||||
|
mRoot = removeUtil(mRoot, key);
|
||||||
|
if (mRoot) mRoot->mParent = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* maxNode(Node* head) const {
|
||||||
|
if (!head) return nullptr;
|
||||||
|
while (head->mRight != nullptr) {
|
||||||
|
head = head->mRight;
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* minNode(Node* head) const {
|
||||||
|
if (!head) return nullptr;
|
||||||
|
while (head->mLeft != nullptr) {
|
||||||
|
head = head->mLeft;
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* find(KeyArg key) const {
|
||||||
|
Node* iter = mRoot;
|
||||||
|
while (true) {
|
||||||
|
if (!iter) return nullptr;
|
||||||
|
if (iter->exactNode(key)) return iter;
|
||||||
|
if (iter->descentLeft(key)) {
|
||||||
|
key = iter->keyInLeftSubtree(key);
|
||||||
|
iter = iter->mLeft;
|
||||||
|
} else {
|
||||||
|
key = iter->keyInRightSubtree(key);
|
||||||
|
iter = iter->mRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* findLessOrEq(KeyArg key) const {
|
||||||
|
Node* iter = mRoot;
|
||||||
|
while (true) {
|
||||||
|
if (!iter) return nullptr;
|
||||||
|
if (iter->exactNode(key)) return iter;
|
||||||
|
if (iter->descentLeft(key)) {
|
||||||
|
if (iter->mLeft) {
|
||||||
|
key = iter->keyInLeftSubtree(key);
|
||||||
|
iter = iter->mLeft;
|
||||||
|
} else {
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (iter->mRight) {
|
||||||
|
key = iter->keyInRightSubtree(key);
|
||||||
|
iter = iter->mRight;
|
||||||
|
} else {
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns first invalid node
|
||||||
|
const Node* findInvalidNode(const Node* head) const {
|
||||||
|
if (head == nullptr) return nullptr;
|
||||||
|
|
||||||
|
if (head->mLeft) {
|
||||||
|
// TODO: incomplete test
|
||||||
|
if (!head->descentLeft(head->mLeft->getFindKey(head))) return head;
|
||||||
|
if (head->mLeft->mParent != head) return head;
|
||||||
|
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head->mRight) {
|
||||||
|
if (!head->descentRight(head->mRight->getFindKey(head))) return head;
|
||||||
|
if (head->mRight->mParent != head) return head;
|
||||||
|
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head->mLeft && head->mRight) {
|
||||||
|
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
|
||||||
|
|
||||||
|
if (balance > 1 || balance < -1) return head;
|
||||||
|
|
||||||
|
const Node* ret = findInvalidNode(head->mRight);
|
||||||
|
|
||||||
|
if (ret) return ret;
|
||||||
|
|
||||||
|
return findInvalidNode(head->mLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() { return findInvalidNode(head()) == nullptr; }
|
||||||
|
|
||||||
|
template <typename tFunctor>
|
||||||
|
void traverse(Node* node, bool after, tFunctor functor) {
|
||||||
|
if (!after) functor(node);
|
||||||
|
if (node->mLeft) traverse(node->mLeft, after, functor);
|
||||||
|
if (node->mRight) traverse(node->mRight, after, functor);
|
||||||
|
if (after) functor(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeAll() {
|
||||||
|
if (!mRoot) return;
|
||||||
|
removeUtil(mRoot);
|
||||||
|
mRoot = nullptr;
|
||||||
|
mSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeUtil(Node* node) {
|
||||||
|
if (node->mLeft) removeUtil(node->mLeft);
|
||||||
|
if (node->mRight) removeUtil(node->mRight);
|
||||||
|
deleteNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <class tArchiver>
|
||||||
|
void archiveWrite(tArchiver& file) const {
|
||||||
|
FAIL("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class tArchiver>
|
||||||
|
void archiveRead(tArchiver&) {
|
||||||
|
FAIL("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void deleteNode(Node* node) {
|
inline void deleteNode(Node* node) {
|
||||||
|
|
@ -243,134 +376,9 @@ namespace tp {
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
private:
|
||||||
AvlTree() { MODULE_SANITY_CHECK(gModuleContainers) }
|
Node* mRoot = nullptr;
|
||||||
|
ualni mSize = 0;
|
||||||
[[nodiscard]] ualni size() const { return mSize; }
|
Allocator mAlloc;
|
||||||
|
|
||||||
Node* head() const { return this->mRoot; }
|
|
||||||
|
|
||||||
void insert(KeyArg key, DataArg data) {
|
|
||||||
mRoot = insertUtil(mRoot, key, data);
|
|
||||||
mRoot->mParent = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(KeyArg key) {
|
|
||||||
mRoot = removeUtil(mRoot, key);
|
|
||||||
if (mRoot) mRoot->mParent = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* maxNode(Node* head) const {
|
|
||||||
if (!head) return nullptr;
|
|
||||||
while (head->mRight != nullptr) {
|
|
||||||
head = head->mRight;
|
|
||||||
}
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* minNode(Node* head) const {
|
|
||||||
if (!head) return nullptr;
|
|
||||||
while (head->mLeft != nullptr) {
|
|
||||||
head = head->mLeft;
|
|
||||||
}
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* find(KeyArg key) const {
|
|
||||||
Node* iter = mRoot;
|
|
||||||
while (true) {
|
|
||||||
if (!iter) return nullptr;
|
|
||||||
if (iter->exactNode(key)) return iter;
|
|
||||||
if (iter->descentLeft(key)) {
|
|
||||||
key = iter->keyInLeftSubtree(key);
|
|
||||||
iter = iter->mLeft;
|
|
||||||
} else {
|
|
||||||
key = iter->keyInRightSubtree(key);
|
|
||||||
iter = iter->mRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* findLessOrEq(KeyArg key) const {
|
|
||||||
Node* iter = mRoot;
|
|
||||||
while (true) {
|
|
||||||
if (!iter) return nullptr;
|
|
||||||
if (iter->exactNode(key)) return iter;
|
|
||||||
if (iter->descentLeft(key)) {
|
|
||||||
if (iter->mLeft) {
|
|
||||||
key = iter->keyInLeftSubtree(key);
|
|
||||||
iter = iter->mLeft;
|
|
||||||
} else {
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (iter->mRight) {
|
|
||||||
key = iter->keyInRightSubtree(key);
|
|
||||||
iter = iter->mRight;
|
|
||||||
} else {
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns first invalid node
|
|
||||||
const Node* findInvalidNode(const Node* head) const {
|
|
||||||
if (head == nullptr) return nullptr;
|
|
||||||
|
|
||||||
if (head->mLeft) {
|
|
||||||
// TODO: incomplete test
|
|
||||||
if (!head->descentLeft(head->mLeft->getFindKey(head))) return head;
|
|
||||||
if (head->mLeft->mParent != head) return head;
|
|
||||||
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (head->mRight) {
|
|
||||||
if (!head->descentRight(head->mRight->getFindKey(head))) return head;
|
|
||||||
if (head->mRight->mParent != head) return head;
|
|
||||||
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (head->mLeft && head->mRight) {
|
|
||||||
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
|
|
||||||
|
|
||||||
if (balance > 1 || balance < -1) return head;
|
|
||||||
|
|
||||||
const Node* ret = findInvalidNode(head->mRight);
|
|
||||||
|
|
||||||
if (ret) return ret;
|
|
||||||
|
|
||||||
return findInvalidNode(head->mLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() { return findInvalidNode(head()) == nullptr; }
|
|
||||||
|
|
||||||
template <typename tFunctor>
|
|
||||||
void traverse(Node* node, bool after, tFunctor functor) {
|
|
||||||
if (!after) functor(node);
|
|
||||||
if (node->mLeft) traverse(node->mLeft, after, functor);
|
|
||||||
if (node->mRight) traverse(node->mRight, after, functor);
|
|
||||||
if (after) functor(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeAll() {
|
|
||||||
traverse(mRoot, true, [this](Node* node) { deleteNode(node); });
|
|
||||||
mRoot = nullptr;
|
|
||||||
mSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <class tArchiver>
|
|
||||||
void archiveWrite(tArchiver& file) const {
|
|
||||||
FAIL("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class tArchiver>
|
|
||||||
void archiveRead(tArchiver&) {
|
|
||||||
FAIL("not implemented")
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue