当前位置: 首页 > news >正文

php网站制作工具百度网页游戏

php网站制作工具,百度网页游戏,专业微信网站建设公司首选公司,网络科技公司帮高校建设网站C手撕AVL树 1、AVL树的概念2、AVL树的结构3、AVL树的插入3.1、大概过程3.2、更新平衡因子3.3、更新平衡因子代码3.4、左单旋3.5、右单旋3.6、右左双旋3.7、左右双旋 4、AVL树的删除5、AVL树的查找6、AVL树的平衡检测7、AVL树的其他函数完整代码 1、AVL树的概念 二叉搜索树虽可…

C++手撕AVL树

  • 1、AVL树的概念
  • 2、AVL树的结构
  • 3、AVL树的插入
    • 3.1、大概过程
    • 3.2、更新平衡因子
    • 3.3、更新平衡因子代码
    • 3.4、左单旋
    • 3.5、右单旋
    • 3.6、右左双旋
    • 3.7、左右双旋
  • 4、AVL树的删除
  • 5、AVL树的查找
  • 6、AVL树的平衡检测
  • 7、AVL树的其他函数
  • 完整代码

1、AVL树的概念

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

AVL树实现这里我们引入一个平衡因子(balance factor)的概念,每个结点都有一个平衡因子,任何结点的平衡因子等于右子树的高度减去左子树的高度,也就是说任何结点的平衡因子等于0/1/-1,AVL树并不是必须要平衡因子,但是有了平衡因子可以更方便我们去进⾏观察和控制树是否平衡,就像一个风向标一样。

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
1、它的左右子树都是AVL树。
2、左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)。

平衡因子的计算我们统一用右边高度减去左边高度,后面的实现也是如此。当然也可以反过来。
在这里插入图片描述
思考一下为什么AVL树是高度平衡搜索二叉树,要求高度差不超过1,而不是高度差是0呢?0不是更好的平衡吗?画画图分析我们发现,不是不想这样设计,而是有些情况是做不到高度差是0的。比如一棵树是2个结点,4个结点等情况下,高度差最好就是1,无法作为高度差是0。而如果高度差是2/3/4…呢?也是不行的,因为这样在插入删除时的旋转调整将会非常麻烦。

下面对AVL树的效率进行分析:
在这里插入图片描述


2、AVL树的结构

节点的结构是三叉链,需要存储父节点的指针,还需要存储bf平衡因子变量。存储父节点的指针是为了在更新平衡因子的时候可以快速找到父节点。
然后我们这里就直接实现key/value模型了,所以需要两个模板参数,分别用K、V来表示,通过pair存储。

template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf;AVLTreeNode(const pair<K, V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_bf(0){}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:private:Node* _root = nullptr;
};

3、AVL树的插入

3.1、大概过程

这里的插入代码和我们之前写的二叉搜索树是类似的,只不过由于插入之后平衡因子可能发生变化,例如变成2/-2,那么就需要调整平衡并更新平衡因子,所以比二叉搜索树多了一步更新平衡因子的过程。

bool Insert(const pair<K, V>& kv)
{if (_root == nullptr){_root = new Node(kv);return false;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first)parent->_right = cur;elseparent->_left = cur;cur->_parent = parent;// 更新平衡因子// ...return true;
}

3.2、更新平衡因子

更新规则:
1、新增节点在父节点的左侧,父节点的平衡因子--。
2、新增节点在父节点的右侧,父节点的平衡因子++。
3、更新后父节点的平衡因子==0,说明父节点所在的子树高度没有发生变化,不会影响祖先,不用再沿着到根节点的路径往上更新,更新结束。
4、更新后父节点的平衡因子==1/-1,说明父节点所在的子树高度发生了变化,会影响祖先,需要沿着到根节点的路径往上更新。
5、更新后父节点的平衡因子==2/-2,说明父节点所在的子树高度变化并且不平衡,需要对父节点所在的子树旋转并更新平衡因子。由于旋转后父节点所在子树高度并没有增加,所以不需要再向上更新,更新结束。
6、若更新到根节点,则停止。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


3.3、更新平衡因子代码

while (parent)
{if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}break;}else{assert(false);}
}

正常情况下,节点的平衡因子要么是0,±1,±2,不会是其他值,但是说不准我们写的代码有bug,所以对于其他值我们直接assert终止程序。


3.4、左单旋

在这里插入图片描述

代码如下:

void RotateL(Node* parent)
{Node* cur = parent->_right;Node* curleft = cur->_left;Node* ppnode = parent->_parent;parent->_right = curleft;if (curleft) curleft->_parent = parent;cur->_left = parent;parent->_parent = cur;if (_root == parent){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;
}

3.5、右单旋

在这里插入图片描述

代码如下:

void RotateR(Node* parent)
{Node* cur = parent->_left;Node* curright = cur->_right;Node* ppnode = parent->_parent;parent->_left = curright;if (curright)curright->_parent = parent;cur->_right = parent;parent->_parent = cur;if (_root == parent){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;
}

3.6、右左双旋

在这里插入图片描述

代码如下:

void RotateRL(Node* parent)
{Node* cur = parent->_right;Node* curleft = cur->_left;int bf = curleft->_bf;	RotateR(cur);RotateL(parent);if (bf == 0){curleft->_bf = 0;parent->_bf = 0;cur->_bf = 0;}else if (bf == -1){curleft->_bf = 0;parent->_bf = 0;cur->_bf = 1;}else if (bf == 1){curleft->_bf = 0;parent->_bf = -1;cur->_bf = 0;}else{assert(false);}
}

这里bf==0这种情况不需要写,包括bf==1和bf==-1这两种情况中平衡因子=0的也不需要赋值,只需要写出平衡因子不为0的赋值,因为在我们写的左旋和右旋函数中已经将平衡因子修改为0了。
这里我们三种情况分别写出来是为了对应上图的分析,写出来更加清晰、好理解。


3.7、左右双旋

在这里插入图片描述

代码如下:

void RotateLR(Node* parent)
{Node* cur = parent->_left;Node* curright = cur->_right;int bf = curright->_bf;RotateL(cur);RotateR(parent);if (bf == 0){curright->_bf = 0;cur->_bf = 0;parent->_bf = 0;}else if (bf == -1){curright->_bf = 0;cur->_bf = 0;parent->_bf = 1;}else if (bf == 1){curright->_bf = 0;cur->_bf = -1;parent->_bf = 0;}else{assert(false);}
}

4、AVL树的删除

在这里插入图片描述

代码如下:

bool Erase(const K& key) {Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < key){parent = cur;cur = cur->_right;}else if (cur->_kv.first > key){parent = cur;cur = cur->_left;}else{if (cur->_left == nullptr)	// 左边为空{if (_root == cur){_root = cur->_right;if (_root)_root->_parent = nullptr;delete cur;return true;}}else if (cur->_right == nullptr) // 右边为空{if (_root == cur){_root = cur->_left;if (_root)_root->_parent = nullptr;delete cur;return true;}}else // 左右都不为空,寻找替换节点{parent = cur;Node* leftMax = cur->_left;while (leftMax->_right){parent = leftMax;leftMax = leftMax->_right;}cur->_kv.first = leftMax->_kv.first;cur->_kv.second = leftMax->_kv.second;cur = leftMax;}break;}}// 找不到直接返回if (cur == nullptr) return false;Node* del = cur;Node* delParent = parent;while (parent){if (parent->_left == cur){	parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0){cur = parent;parent = parent->_parent;}else if (parent->_bf == 1 || parent->_bf == -1){break;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == -2){if (parent->_left->_bf == 0){cur = parent->_left;RotateR(parent);cur->_bf = 1;parent->_bf = -1;break;}else if (parent->_left->_bf == -1){cur = parent->_left;RotateR(parent);}else // parent->_left->_bf == 1;{cur = parent->_left->_right;RotateLR(parent);}}else // parent->_bf == 2{if (parent->_right->_bf == 0){cur = parent->_right;RotateL(parent);cur->_bf = -1;parent->_bf = 1;break;}else if (parent->_right->_bf == 1){cur = parent->_right;RotateL(parent);}else{cur = parent->_right->_left;RotateRL(parent);}}parent = cur->_parent;}else{assert(false);}}cur = del, parent = delParent;if (cur->_left == nullptr){if (parent->_left == cur)parent->_left = cur->_right;elseparent->_right = cur->_right;if (cur->_right)cur->_right->_parent = parent;}else{if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;if (cur->_left)cur->_left->_parent = parent;}delete cur;return true;
}

5、AVL树的查找

Node* Find(const K& key)
{Node* cur = _root;while (cur){if (cur->_kv.first < key)cur = cur->_right;else if (cur->_kv.first > key)cur = cur->_left;elsereturn cur;}return nullptr;
}

6、AVL树的平衡检测

bool IsBalance(){return IsBalance(_root);}int Height()
{return Height(_root);
}bool IsBalance(Node* root)
{if (root == nullptr) return true;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << "平衡因子异常:" << root->_kv.first << "->" << root->_bf << endl;return false;}return abs(leftHeight - rightHeight) < 2&& IsBalance(root->_left)&& IsBalance(root->_right);
}int Height(Node* root)
{if (root == nullptr) return 0;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

通过IsBalance函数来判断树中的平衡因子计算是否正确,如果存在异常就会打印输出信息。
同时为了计算平衡因子,需要求出左右高度然后相减,所以还需要实现Height函数获取树的高度。


7、AVL树的其他函数

这里实现构造函数、拷贝构造函数、赋值运算符重载、析构函数、中序遍历函数。基本上类似前面的二叉搜索树。

AVLTree():_root(nullptr)
{}AVLTree(const AVLTree<K, V>& t):_root(nullptr)
{_root = Copy(t._root, nullptr);
}AVLTree<K, V>& operator=(AVLTree<K, V> t)
{swap(_root, t._root);return *this;
}~AVLTree()
{Destroy(_root);
}void InOrder()
{InOrder(_root);cout << endl;
}Node* Copy(Node* root, Node* parent)
{if (root == nullptr) return nullptr;Node* copy = new Node(root->_kv);copy->_bf = root->_bf;copy->_parent = parent;copy->_left = Copy(root->_left, copy);copy->_right = Copy(root->_right, copy);return copy;
}void Destroy(Node*& root)
{if (root == nullptr) return;Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;
}void InOrder(Node* root)
{if (root == nullptr) return;InOrder(root->_left);cout << root->_kv.first << " ";InOrder(root->_right);
}

完整代码

#pragma oncetemplate<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf;AVLTreeNode(const pair<K, V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_bf(0){}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:AVLTree():_root(nullptr){}AVLTree(const AVLTree<K, V>& t):_root(nullptr){_root = Copy(t._root, nullptr);}AVLTree<K, V>& operator=(AVLTree<K, V> t){swap(_root, t._root);return *this;}~AVLTree(){Destroy(_root);}bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return false;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first)parent->_right = cur;elseparent->_left = cur;cur->_parent = parent;while (parent){if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}break;}else{assert(false);}}return true;}bool Erase(const K& key) {Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < key){parent = cur;cur = cur->_right;}else if (cur->_kv.first > key){parent = cur;cur = cur->_left;}else{if (cur->_left == nullptr)	// 左边为空{if (_root == cur){_root = cur->_right;if (_root)_root->_parent = nullptr;delete cur;return true;}}else if (cur->_right == nullptr) // 右边为空{if (_root == cur){_root = cur->_left;if (_root)_root->_parent = nullptr;delete cur;return true;}}else // 左右都不为空,寻找替换节点{parent = cur;Node* leftMax = cur->_left;while (leftMax->_right){parent = leftMax;leftMax = leftMax->_right;}cur->_kv.first = leftMax->_kv.first;cur->_kv.second = leftMax->_kv.second;cur = leftMax;}break;}}// 找不到直接返回if (cur == nullptr) return false;Node* del = cur;Node* delParent = parent;while (parent){if (parent->_left == cur){	parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0){cur = parent;parent = parent->_parent;}else if (parent->_bf == 1 || parent->_bf == -1){break;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == -2){if (parent->_left->_bf == 0){cur = parent->_left;RotateR(parent);cur->_bf = 1;parent->_bf = -1;break;}else if (parent->_left->_bf == -1){cur = parent->_left;RotateR(parent);}else // parent->_left->_bf == 1;{cur = parent->_left->_right;RotateLR(parent);}}else // parent->_bf == 2{if (parent->_right->_bf == 0){cur = parent->_right;RotateL(parent);cur->_bf = -1;parent->_bf = 1;break;}else if (parent->_right->_bf == 1){cur = parent->_right;RotateL(parent);}else{cur = parent->_right->_left;RotateRL(parent);}}parent = cur->_parent;}else{assert(false);}}cur = del, parent = delParent;if (cur->_left == nullptr){if (parent->_left == cur)parent->_left = cur->_right;elseparent->_right = cur->_right;if (cur->_right)cur->_right->_parent = parent;}else{if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;if (cur->_left)cur->_left->_parent = parent;}delete cur;return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_kv.first < key)cur = cur->_right;else if (cur->_kv.first > key)cur = cur->_left;elsereturn cur;}return nullptr;}bool IsBalance(){return IsBalance(_root);}int Height(){return Height(_root);}void InOrder(){InOrder(_root);cout << endl;}private:Node* Copy(Node* root, Node* parent){if (root == nullptr) return nullptr;Node* copy = new Node(root->_kv);copy->_bf = root->_bf;copy->_parent = parent;copy->_left = Copy(root->_left, copy);copy->_right = Copy(root->_right, copy);return copy;}void Destroy(Node*& root){if (root == nullptr) return;Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;}void InOrder(Node* root){if (root == nullptr) return;InOrder(root->_left);cout << root->_kv.first << " ";InOrder(root->_right);}bool IsBalance(Node* root){if (root == nullptr) return true;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << "平衡因子异常:" << root->_kv.first << "->" << root->_bf << endl;return false;}return abs(leftHeight - rightHeight) < 2&& IsBalance(root->_left)&& IsBalance(root->_right);}int Height(Node* root){if (root == nullptr) return 0;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}void RotateL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;Node* ppnode = parent->_parent;parent->_right = curleft;if (curleft) curleft->_parent = parent;cur->_left = parent;parent->_parent = cur;if (_root == parent){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;}void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;Node* ppnode = parent->_parent;parent->_left = curright;if (curright)curright->_parent = parent;cur->_right = parent;parent->_parent = cur;if (_root == parent){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;}void RotateRL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;int bf = curleft->_bf;	RotateR(cur);RotateL(parent);if (bf == 0){curleft->_bf = 0;parent->_bf = 0;cur->_bf = 0;}else if (bf == -1){curleft->_bf = 0;parent->_bf = 0;cur->_bf = 1;}else if (bf == 1){curleft->_bf = 0;parent->_bf = -1;cur->_bf = 0;}else{assert(false);}}void RotateLR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;int bf = curright->_bf;RotateL(cur);RotateR(parent);if (bf == 0){curright->_bf = 0;cur->_bf = 0;parent->_bf = 0;}else if (bf == -1){curright->_bf = 0;cur->_bf = 0;parent->_bf = 1;}else if (bf == 1){curright->_bf = 0;cur->_bf = -1;parent->_bf = 0;}else{assert(false);}}
private:Node* _root = nullptr;
};
http://www.tj-hxxt.cn/news/108824.html

相关文章:

  • 上海浦东网站建设百度推广运营工作是什么
  • 网站做联盟收入免费html网页模板
  • 设计素材网站p兰州模板网站seo价格
  • qq炫舞做浴缸的网站百度链接提交收录入口
  • 捡个校花做老婆是哪个网站的重庆企业网站排名优化
  • 夸网站做的好怎么夸在线识别图片
  • 太原网站建设的公司排名网上售卖平台有哪些
  • 青岛做网站企业神马搜索seo优化排名
  • 哈尔滨网站设计多少钱手机如何创建网站
  • 东乡哪里有做网站快速网站搭建
  • 定制类电商平台天津seo优化排名
  • 响应式网站制作公司seo比较好的公司
  • 网站后台一般是用什么做的中国最新军事新闻直播
  • 太原网站建设推广微博上如何做网站推广
  • 怎么做app和网站购物中国足球世界排名
  • 做电影网站如何不侵权seo站长优化工具
  • 大型网站建设用什么系统好seo综合优化公司
  • 做建筑设计网站百度推广收费标准
  • 佛山营销网站开发怎么选软件开发工具
  • 网站功能配置腾讯云域名
  • 社会保险网站nba湖人最新新闻
  • 网页设计与制作的实训报告怎样写快速排名生客seo
  • 做网站banner课程封面搜索优化的培训免费咨询
  • 杭州旅游团购网站建设免费网站推广群发软件
  • 贝壳找房网站做销售互联网网络推广
  • 最简单的做网站的工具互联网推广的好处
  • 网站开发前期调研网络营销与市场营销的区别
  • 快速做网站关键词排名百度搜索引擎推广怎么弄
  • 英国房产网站大全成都新闻今日最新消息
  • 东莞高端模板建站网店运营工资一般多少