如何解决AVLTree没有统一旋转操作的问题,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
最近疫情比较严重,只能在家里休息,利用休息之余,我用C++把AVL树实现了一遍
大学老师只讲一些比较简单的数据结构和算法,这些高级数据结构还是需要自己主动学习并且动手来实现的,
从前只听说过AVLTree,我从看书了解原理到把它一点一点写出来最后在调试一共花了大概3天的时间。应该已经算很长时间了。
一般情况下AVL树是不用我么自己写的,但是为了有一份已经实现的代码作为我以后再来回顾算法实现的依照,我还是决定对自己狠一些把它实现了一遍
以下代码均采用C++11 标准
在ubuntu 18.04上经过编译和调试
/* * BinarySearchTree.h * 1. 添加元素时需自己做判断元素是否合法 * 2. 除层序遍历外,本源代码均采用递归遍历,若要减少栈的消耗,应该实现递归遍历 * 3. 本代码实现的AVL树没有统一旋转操作,采用分情况讨论LL,LR,RR,RL来进行树的平衡 * Created on: 2020年1月29日 * Author: LuYonglei */#ifndef SRC_BINARYSEARCHTREE_H_#define SRC_BINARYSEARCHTREE_H_#include <queue>template<typename Element>class BinarySearchTree {public: BinarySearchTree(int (*cmp)(Element e1, Element e2)); //比较函数指针 virtual ~BinarySearchTree(); int size(); //元素的数量 bool isEmpty(); //是否为空 void clear() { //清空所有元素 NODE *node = root_; root_ = nullptr; using namespace std; queue<NODE*> q; q.push(node); while (!q.empty()) { NODE *tmp = q.front(); if (tmp->left != nullptr) q.push(tmp->left); if (tmp->right != nullptr) q.push(tmp->right); delete tmp; q.pop(); } } void add(Element e) { //添加元素 add(e, cmp_); } void remove(Element e) { //删除元素 remove(Node(e, cmp_)); } bool contains(Element e) { //是否包含某元素 return Node(e, cmp_) != nullptr; } void preorderTraversal(bool (*visitor)(Element &e)) { //前序遍历 if (visitor == nullptr) return; bool stop = false; //停止标志,若stop为true,则停止遍历 preorderTraversal(root_, stop, visitor); } void inorderTraversal(bool (*visitor)(Element &e)) { //中序遍历 if (visitor == nullptr) return; bool stop = false; //停止标志,若stop为true,则停止遍历 inorderTraversal(root_, stop, visitor); } void postorderTraversal(bool (*visitor)(Element &e)) { //后序遍历 if (visitor == nullptr) return; bool stop = false; //停止标志,若stop为true,则停止遍历 postorderTraversal(root_, stop, visitor); } void levelOrderTraversal(bool (*visitor)(Element &e)) { //层序遍历,迭代实现 if (visitor == nullptr) return; levelOrderTraversal(root_, visitor); } int height() { //树的高度 return height(root_); } bool isComplete() { //判断是否是完全二叉树 return isComplete(root_); }private: int size_; typedef struct _Node { Element e; _Node *parent; _Node *left; _Node *right; int height; //节点的高度 _Node(Element e_, _Node *parent_) : e(e_), parent(parent_), left(nullptr), right(nullptr), height(1) { //节点构造函数 } inline bool isLeaf() { return (left == nullptr && right == nullptr); } inline bool hasTwoChildren() { return (left != nullptr && right != nullptr); } inline int balanceFactor() { //获得节点的平衡因子 int leftHeight = left == nullptr ? 0 : left->height; //获得左子树的高度 int rightHeight = right == nullptr ? 0 : right->height; //获得右子树的高度 return leftHeight - rightHeight; } inline bool isBalanced() { //判断node是否平衡 int balanceFactor_ = balanceFactor(); return balanceFactor_ >= -1 && balanceFactor_ <= 1; //平衡因子为-1,0,1则返回true } inline void updateHeight() { //更新节点的高度 int leftHeight = left == nullptr ? 0 : left->height; //获得左子树的高度 int rightHeight = right == nullptr ? 0 : right->height; //获得右子树的高度 height = 1 + (leftHeight > rightHeight ? leftHeight : rightHeight); //把节点高度更新为左右子树最大的高度+1 } inline bool isLeftChild() { //判断节点是否是父亲节点的左子结点 return parent != nullptr && parent->left == this; } inline bool isRightChild() { //判断节点是否是父亲节点的右子结点 return parent != nullptr && parent->right == this; } inline _Node* tallerChild() { //获得高度更高的子树 int leftHeight = left == nullptr ? 0 : left->height; //获得左子树的高度 int rightHeight = right == nullptr ? 0 : right->height; //获得右子树的高度 if (leftHeight > rightHeight) return left; if (leftHeight < rightHeight) return right; return isLeftChild() ? left : right; } } NODE; NODE *root_; int (*cmp_)(Element e1, Element e2); //为实现树的排序的个性化配置,私有成员保存一个比较函数指针 NODE* Node(Element e, int (*cmp_)(Element e1, Element e2)) { //返回e元素所在的节点 NODE *node = root_; while (node != nullptr) { int cmp = cmp_(e, node->e); if (cmp == 0) //找到了元素 return node; if (cmp > 0) { //待寻找元素大于节点存储的元素 node = node->right; } else { //待寻找元素小于节点存储的元素 node = node->left; } } return nullptr; } NODE* predecessor(NODE *node) { //返回node的前驱节点 if (node == nullptr) return nullptr; //前驱节点在左子树 NODE *tmp = node->left; if (tmp != nullptr) { while (tmp->right != nullptr) tmp = tmp->right; return tmp; } //从父节点,祖父节点中寻找前驱节点 while (node->parent != nullptr && node == node->parent->left) { node = node->parent; } return node->parent; } NODE* successor(NODE *node) { //返回node的后继节点 if (node == nullptr) return nullptr; //后继节点在右子树 NODE *tmp = node->right; if (tmp != nullptr) { while (tmp->left != nullptr) tmp = tmp->left; return tmp; } //从父节点,祖父节点中寻找后继节点 while (node->parent != nullptr && node == node->parent->right) { node = node->parent; } return node->parent; } void afterRotate(NODE *gNode, NODE *pNode, NODE *child) { //在左旋转与右旋转中统一调用 pNode->parent = gNode->parent; if (gNode->isLeftChild()) gNode->parent->left = pNode; else if (gNode->isRightChild()) gNode->parent->right = pNode; else //此时gNode->parent 为nullptr,gNode为root节点 root_ = pNode; if (child != nullptr) child->parent = gNode; gNode->parent = pNode; //左右子树发生变化,所以要更新高度 gNode->updateHeight(); pNode->updateHeight(); } void rotateLeft(NODE *gNode) { //对gNode进行左旋转 NODE *pNode = gNode->right; NODE *child = pNode->left; gNode->right = child; pNode->left = gNode; afterRotate(gNode, pNode, child); } void rotateRight(NODE *gNode) { //对gNode进行右旋转 NODE *pNode = gNode->left; NODE *child = pNode->right; gNode->left = child; pNode->right = gNode; afterRotate(gNode, pNode, child); } void rebalance(NODE *gNode) { //恢复平衡,grand为高度最低的不平衡节点 NODE *pNode = gNode->tallerChild(); NODE *nNode = pNode->tallerChild(); if (pNode->isLeftChild()) { if (nNode->isLeftChild()) { //LL /* * gNode * / 对gNode右旋 * pNode ====> pNode * / / \ * nNode nNode gNode */ rotateRight(gNode); } else { //LR /* * gNode gNode * / 对pNode左旋 / 对gNode右旋 * pNode ====> nNode ====> nNode * \ / / \ * nNode pNode pNode gNode */ rotateLeft(pNode); rotateRight(gNode); } } else { if (nNode->isLeftChild()) { //RL /* * gNode gNode * \ 对pNode右旋 \ 对gNode左旋 * pNode ====> nNode ====> nNode * / \ / \ * nNode pNode gNode pNode */ rotateRight(pNode); rotateLeft(gNode); } else { //RR /* * gNode * \ 对gNode左旋 * pNode ====> pNode * \ / \ * nNode gNode nNode */ rotateLeft(gNode); } } } void afterAdd(NODE *node) { //添加node之后的调整 if (node == nullptr) return; node = node->parent; while (node != nullptr) { if (node->isBalanced()) { //如果节点平衡,则对其更新高度 node->updateHeight(); } else { //此时对第一个不平衡节点操作,使其平衡 rebalance(node); //整棵树恢复平衡后,跳出循环 break; } node = node->parent; } } void add(Element e, int (*cmp_)(Element e1, Element e2)) { //当树为空时,添加的节点作为树的根节点 if (root_ == nullptr) { root_ = new NODE(e, nullptr); size_++; //插入一个根节点之后进行调整 afterAdd(root_); return; } //当添加的节点不是第一个节点 NODE *parent = root_; NODE *node = root_; int cmp = 0; //比较结果 while (node != nullptr) { parent = node; //保存父节点 cmp = cmp_(e, node->e); //由函数指针来比较 if (cmp > 0) { node = node->right; //添加的元素大于节点中的元素 } else if (cmp < 0) { node = node->left; //添加的元素小于节点中的元素 } else { node->e = e; //相等时就覆盖 return; //添加的元素等于节点中的元素,直接返回 } } //判断要插入父节点的哪个位置 NODE *newNode = new NODE(e, parent); //为新元素创建节点 if (cmp > 0) { parent->right = newNode; //添加的元素大于节点中的元素 } else { parent->left = newNode; //添加的元素小于节点中的元素 } size_++; //添加一个新节点之后进行调整 afterAdd(newNode); } void afterRemove(NODE *node) { //删除node之后的调整 if (node == nullptr) return; node = node->parent; while (node != nullptr) { if (node->isBalanced()) { //如果节点平衡,则对其更新高度 node->updateHeight(); } else { //此时对不平衡节点操作,使其平衡 rebalance(node); } node = node->parent; } } void remove(NODE *node_) { //删除某一节点 if (node_ == nullptr) return; size_--; //优先删除度为2的节点 if (node_->hasTwoChildren()) { NODE *pre = successor(node_); //找到node_的后继节点 node_->e = pre->e; //用后继节点的值覆盖度为2的节点的值 //删除后继节点(后继节点的度只能为1或0) node_ = pre; } //此时node_的度必然为0或1 NODE *replacement = node_->left != nullptr ? node_->left : node_->right; if (replacement != nullptr) { //node_的度为1 replacement->parent = node_->parent; if (node_->parent == nullptr) //度为1的根节点 root_ = replacement; else if (node_->parent->left == node_) node_->parent->left = replacement; else node_->parent->right = replacement; //所有删除操作准备完成,准备释放节点内存前进行平衡操作 afterRemove(node_); delete node_; } else if (node_->parent == nullptr) { //node_是叶子节点,也是根节点 root_ = nullptr; //所有删除操作准备完成,准备释放节点内存前进行平衡操作 afterRemove(node_); delete node_; } else { //node_是叶子节点,但不是根节点 if (node_->parent->left == node_) node_->parent->left = nullptr; else node_->parent->right = nullptr; //所有删除操作准备完成,准备释放节点内存前进行平衡操作 afterRemove(node_); delete node_; } } void preorderTraversal(NODE *node, bool &stop, bool (*visitor)(Element &e)) { //递归实现前序遍历 if (node == nullptr || stop == true) return; stop = visitor(node->e); preorderTraversal(node->left, stop, visitor); preorderTraversal(node->right, stop, visitor); } void inorderTraversal(NODE *node, bool &stop, bool (*visitor)(Element &e)) { //递归实现中序遍历 if (node == nullptr || stop == true) return; inorderTraversal(node->left, stop, visitor); if (stop == true) return; stop = visitor(node->e); inorderTraversal(node->right, stop, visitor); } void postorderTraversal(NODE *node, bool &stop, bool (*visitor)(Element &e)) { //递归实现后序遍历 if (node == nullptr || stop == true) return; postorderTraversal(node->left, stop, visitor); postorderTraversal(node->right, stop, visitor); if (stop == true) return; stop = visitor(node->e); } void levelOrderTraversal(NODE *node, bool (*visitor)(Element &e)) { if (node == nullptr) return; using namespace std; queue<NODE*> q; q.push(node); while (!q.empty()) { NODE *node = q.front(); if (visitor(node->e) == true) return; if (node->left != nullptr) q.push(node->left); if (node->right != nullptr) q.push(node->right); q.pop(); } } int height(NODE *node) { //某一节点的高度 return node->height; } bool isComplete(NODE *node) { if (node == nullptr) return false; using namespace std; queue<NODE*> q; q.push(node); bool leaf = false; //判断接下来的节点是否为叶子节点 while (!q.empty()) { NODE *node = q.front(); if (leaf && !node->isLeaf()) //判断叶子节点 return false; if (node->left != nullptr) { q.push(node->left); } else if (node->right != nullptr) { //node->left == nullptr && node->right != nullptr return false; } if (node->right != nullptr) { q.push(node->right); } else { //node->right==nullptr leaf = true; } q.pop(); } return true; }};template<typename Element>BinarySearchTree<Element>::BinarySearchTree(int (*cmp)(Element e1, Element e2)) : size_(0), root_(nullptr), cmp_(cmp) { //树的构造函数}template<typename Element>BinarySearchTree<Element>::~BinarySearchTree() { // 析构函数 clear();}template<typename Element>inline int BinarySearchTree<Element>::size() { //返回元素个数 return size_;}template<typename Element>inline bool BinarySearchTree<Element>::isEmpty() { //判断是否为空树 return size_ == 0;}#endif /* SRC_BINARYSEARCHTREE_H_ */main方法/* * main.cpp * * Created on: 2020年1月29日 * Author: LuYonglei */#include "BinarySearchTree.h"#include <iostream>#include <time.h>using namespace std;template<typename Element>int compare(Element e1, Element e2) { //比较函数,相同返回0,e1<e2返回-1,e1>e2返回1 return e1 == e2 ? 0 : (e1 < e2 ? -1 : 1);}template<typename Elemnet>bool visitor(Elemnet &e) { cout << e << " "; cout << endl; return false; //若返回true,则在遍历时会退出}int main(int argc, char **argv) { BinarySearchTree<double> a(compare);// a.add(85);// a.add(19);// a.add(69);// a.add(3);// a.add(7);// a.add(99);// a.add(95);// a.add(2);// a.add(1);// a.add(70);// a.add(44);// a.add(58);// a.add(11);// a.add(21);// a.add(14);// a.add(93);// a.add(57);// a.add(4);// a.add(56);// a.remove(99);// a.remove(85);// a.remove(95); clock_t start = clock(); for (int i = 0; i < 1000000; i++) { a.add(i); } for (int i = 0; i < 1000000; i++) { a.remove(i); }// a.inorderTraversal(visitor); clock_t end = clock(); cout << end - start << endl;// cout <<a.height()<< endl;// cout << a.isComplete() << endl;// a.remove(7);// a.clear();// a.levelOrderTraversal(visitor);// cout << endl;// cout<<a.contains(0)<<endl;}
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。