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

怎么做网站推广多少钱网络营销促销方案

怎么做网站推广多少钱,网络营销促销方案,武汉网站建设吧,备案 网站建设方案书怎么写目录 第一节:AVL树的特征 第二节:实现思路 2-1.插入 2-1-1.右单旋 2-1-2.左单旋 2-1-3.左右双旋 2-1-4.右左双旋 2-1-5.总结 2-2.删除 第三节:代码实现 3-1.Node类 3-2.AVLTree类 3-2-1.Insert函数 3-2-2.Height函数 3-2-3.Balance函数 3-…

目录

第一节:AVL树的特征

第二节:实现思路

        2-1.插入

                2-1-1.右单旋

                2-1-2.左单旋

                2-1-3.左右双旋

                2-1-4.右左双旋

                2-1-5.总结

        2-2.删除

第三节:代码实现

        3-1.Node类

        3-2.AVLTree类

                3-2-1.Insert函数

                3-2-2.Height函数

                3-2-3.Balance函数

                3-2-4.其他函数

                 3-2-5.clear函数

第四节:测试

第五节:优化方案

gitee:AVL树 · 转调/C++ - 码云 - 开源中国 

第六章:总结

下期预告:


第一节:AVL树的特征

        如果一个搜索二叉树的结构如下:

                                

        那么当我想找a的时候,时间复杂度就从 log₂n 退化成 n 了。

        究其原因,搜索二叉树没有一个机制让树的整体高度变得更低。

        所以就出现了AVL树,AVL树通过保证每个节点的左右子树高度差不超过[-1,1],保证整棵树的平衡。

        将左右子树高度差抽象成平衡因子,平衡因子=右子树高度-左子树高度,每个节点都要维护自己的平衡因子不超过1。

第二节:实现思路

        2-1.插入

        1.首先按照搜索二叉树的规则进行插入

        2.插入后更新其父亲节点的平衡因子

                a.插入父亲节点的左子树,父亲节点平衡因子--

                b.插入父亲节点的右子树,父亲节点平衡因子++

        3.如果父亲节点平衡因子是-1或者1,说明父亲所在子树的高度改变了,继续更新父亲的父亲节点的平衡因子,若父亲的父亲节点的平衡因子也为-1或者1,继续向上更新,直到平衡因子不为-1或者1;

        如果某个祖先节点的平衡因子更新后为0,说明祖先节点所在子树高度不变了,对祖先之上的节点也没有影响了,不再往上更新;

        如果某个祖先节点的平衡因子为-2或者2,就需要进行旋转处理了:

                2-1-1.右单旋

        当前节点平衡因子为-2 && 其左孩子的平衡因子为-1 进行右单旋

        用长方形表示子树高度,b、c的高度都为h,a的高度为h+1,红色方块为节点新增位置,蓝色字体为节点的平衡因子:

                                        

        60的平衡因子为-2,并且其左孩子30的平衡因子为-1,进行右单旋

        具体的方法是将60的左孩子变成30的右孩子,30的右孩子被"抢走了",就把60变成30的右孩子,最后把60的父亲变成30的父亲。

        这样做之后30和60的平衡因子都变成了0,就不需要再向上更新了。

        可以发现30向右旋转把60顶替了,60向右旋转屈居30,a、b、c从左向右的顺序依然不变。

                2-1-2.左单旋

        当前节点平衡因子为+2 && 其右孩子的平衡因子为+1

                                                

        30的平衡因子为+2,并且其右孩子60的平衡因子为+1,进行左单旋

        

        这样做之后30和60的平衡因子都变成了0,就不需要再向上更新了。

        可以发现60向左旋转把30顶替了,30向左旋转屈居30,a、b、c从左向右的顺序依然不变。

                2-1-3.左右双旋

        当前节点平衡因子为-2 && 其左孩子的平衡因子为+1时进行左右双旋。

        左右双旋有三种不同的情况,它们的旋转逻辑是一样的,但是最后的平衡因子不同。

        旋转逻辑:

        先不看它们的平衡因子,只看节点和子树的交换关系,此时a=h,d=h,b和c有一个等于h-1,另一个等于h,才能保证90的平衡因子为-2,30的平衡因子为1。

            其实就是孙子变成了它爸爸和爷爷共同的父亲,然后仍然保持a、b、c、d的左右顺序 

        (1)如果60自己就是新增的节点

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​    

        

        3个节点的平衡因子都为0,不再向上更新。

        为了便于理解,我使用绿色字母表示新增节点后a、b、c、d的高度。

        (2)如果60的左子树新增节点

        此时60的平衡因子为0,不再向上更新,30的平衡因子为0,90的平衡因子为1

        (3)如果60的右子树新增节点

        此时60的平衡因子为0,不再向上更新,30的平衡因子为-1,90的平衡因子为0

                2-1-4.右左双旋

        当前节点平衡因子为+2 && 其右孩子的平衡因子为-1时进行左右双旋。

        左右双旋也有三种不同的情况,它们的旋转逻辑是一样的,但是最后的平衡因子不同。

         旋转逻辑:

        

        也是孙子变成了它爸爸和爷爷共同的父亲,然后仍然保持a、b、c、d的左右顺序 ,这和左右双旋的结果一致。 

         所以如果是60的左子树b新增节点,旋转后,30、60、90的平衡因子分别是0、0、1;

        如果是60的右子树c新增节点,旋转后,30、60、90的平衡因子分别是-1、0、0;

        如果60本身是新增的节点,旋转后,30、60、90的平衡因子都是0。

                2-1-5.总结

        只要进行旋转后,"辈分"最高的节点的平衡因子都变成了0,说明只要进行过旋转,就不需要再往上更新了。

第三节:代码实现

        将以上思路整理成代码。

        3-1.Node类

        首先创建一个节点类:

        它除了节点的连接和保存的值之外,还需要一个变量_bf来保存平衡因子。

template<class T>
class Node
{
public:Node<T>* _left = nullptr;Node<T>* _right = nullptr;Node<T>* _parent = nullptr;T _val;short _bf = 0;
};

        3-2.AVLTree类

        它是AVL树的具体实现。

class AVLTree
{
private:Node<T>* _root = nullptr; // 保存根节点
};

                3-2-1.Insert函数

        首先完成插入函数,它传入一个值,然后按照搜索二叉树的思路插入节点:

		void Insert(const T& val){// 如果根节点为空,赋值根节点即可if (_root == nullptr){_root = new Node<T>;_root->_val = val;return;}Node<T>* cur = _root;Node<T>* parent = nullptr;while (cur){if (cur->_val < val){parent = cur;cur = cur->_right;}else if (cur->_val > val){parent = cur;cur = cur->_left;}}cur = new Node<T>;cur->_val = val;if (parent->_val < val){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;// 更新祖先节点的平衡因子while (parent){if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}// 继续更新if (abs(parent->_bf) == 1){cur = parent;parent = parent->_parent;continue;}// 不再更新if (parent->_bf == 0){break;}// 如果失衡,进行旋转if (abs(parent->_bf) > 1){Rotate(parent);break;}}}

                3-2-2.Height函数

        它获取某个节点的高度,获得某个节点左右孩子的高度后,就可以计算_bf:

		size_t _Height(Node<T>* root){if (root == nullptr) return 0;return std::max(_Height(root->_left), _Height(root->_right)) + 1;}size_t Height(Node<T>* root){return _Height(root);}

                3-2-3.Balance函数

        AVL树的核心函数,它用来更新节点的平衡因子:

void Rotate(Node<T>* cur)
{// 进行旋转处理,旋转完也不需要继续更新了if (cur->_bf == -2 && cur->_left->_bf == -1) // 右单旋{Node<T>* P = cur;      // 父亲Node<T>* S = P->_left; // 儿子P->_left = S->_right;if (S->_right)S->_right->_parent = P;S->_right = P;if (P != _root){if (P == P->_parent->_left){P->_parent->_left = S;}else if (P == P->_parent->_right){P->_parent->_right = S;}}else{_root = S;}S->_parent = P->_parent;P->_parent = S;P->_bf = 0;S->_bf = 0;}else if (cur->_bf == 2 && cur->_right->_bf == 1) // 左单旋{Node<T>* P = cur;Node<T>* S = P->_right;P->_right = S->_left;if (S->_left)S->_left->_parent = P;S->_left = P;if (P != _root){if (P == P->_parent->_left){P->_parent->_left = S;}else if (P == P->_parent->_right){P->_parent->_right = S;}}else{_root = S;}S->_parent = P->_parent;P->_parent = S;P->_bf = 0;S->_bf = 0;}else if (cur->_bf == -2 && cur->_left->_bf == 1) // 左右双旋{Node<T>* P = cur;      // 父亲Node<T>* S = P->_left; // 儿子Node<T>* G = S->_right;// 孙子P->_left = G->_right;if (G->_right)G->_right->_parent = P;G->_right = P;S->_right = G->_left;if (G->_left)G->_left->_parent = S;G->_left = S;if (P != _root){if (P == P->_parent->_left){P->_parent->_left = G;}else if (P == P->_parent->_right){P->_parent->_right = G;}}else{_root = G;}G->_parent = P->_parent;P->_parent = G;S->_parent = G;if (G->_bf == 1){S->_bf = -1;P->_bf = 0;}else if (G->_bf == -1){S->_bf = 0;P->_bf = 1;}else if (G->_bf == 0){S->_bf = P->_bf = 0;}G->_bf = 0;}else if (cur->_bf == 2 && cur->_right->_bf == -1) // 右左双旋{Node<T>* P = cur;Node<T>* S = P->_right;Node<T>* G = S->_left;P->_right = G->_left;if (G->_left)G->_left->_parent = P;G->_left = P;S->_left = G->_right;if (G->_right)G->_right->_parent = S;G->_right = S;if (P != _root){if (P == P->_parent->_left){P->_parent->_left = G;}else if (P == P->_parent->_right){P->_parent->_right = G;}}else{_root = G;}G->_parent = P->_parent;P->_parent = G;S->_parent = G;if (G->_bf == 1){S->_bf = 0;P->_bf = -1;}else if (G->_bf == -1){S->_bf = 1;P->_bf = 0;}else if (G->_bf == 0){S->_bf = P->_bf = 0;}G->_bf = 0;}
}

                3-2-4.其他函数

        Print 和 IsBalance 用来按升序打印内容和判断每个节点是否都平衡:

	bool IsBalance(){return _IsBalance(_root);}void Print(){_Print(_root);}bool _IsBalance(Node<T>* root){if (root == nullptr) return true;if (abs(root->_bf) > 1) return false;return _IsBalance(root->_left) && _IsBalance(root->_right);}void _Print(Node<T>* root){if (root == nullptr) return;_Print(root->_left);std::cout << root->_val << " ";_Print(root->_right);}

                 3-2-5.clear函数

        因为节点都是new出来的,所以使用清理函数释放空间,析构函数也要调用这个函数:

		void _clear(Node<T>* root){if (root == nullptr) return;_clear(root->_left);_clear(root->_right);delete root;}void clear(){_clear(_root);}~AVLTree(){clear();}

第四节:测试

        插入多个随机数,然后调用 Print 和 IsBalance。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#include "AVLTree.hpp"int main()
{zd::AVLTree<int> tree;srand(time(NULL));int i = 100;while (i--){int x = rand();tree.Insert(x);}tree.Print();if (tree.IsBalance()){printf("true\n");}else{printf("false\n");}return 0;
}

        观察打印结果和最后是否为true即可。

第五节:优化方案

        实际上左右双旋和右左双旋就是左单旋和右单旋的组合,所以可以将左单旋、右单旋封装成函数,供左右单旋和右左单旋调用。

        但是封装的时候G的_bf需要提前保存,因为调用两次单旋之后,G的_bf就改变了:

		void RotateR(Node<T>* cur) // 右单旋{Node<T>* P = cur;Node<T>* S = P->_left;P->_left = S->_right;if (S->_right)S->_right->_parent = P;S->_right = P;if (P != _root){if (P == P->_parent->_left){P->_parent->_left = S;}else if (P == P->_parent->_right){P->_parent->_right = S;}}else{_root = S;}S->_parent = P->_parent;P->_parent = S;P->_bf = 0;S->_bf = 0;}void RotateL(Node<T>* cur) // 左单旋{Node<T>* P = cur;Node<T>* S = P->_right;P->_right = S->_left;if (S->_left)S->_left->_parent = P;S->_left = P;if (P != _root){if (P == P->_parent->_left){P->_parent->_left = S;}else if (P == P->_parent->_right){P->_parent->_right = S;}}else{_root = S;}S->_parent = P->_parent;P->_parent = S;P->_bf = 0;S->_bf = 0;}void RotateLR(Node<T>* cur) // 左右双旋{Node<T>* P = cur;Node<T>* S = P->_left;Node<T>* G = S->_right;short bf = G->_bf;RotateL(S);RotateR(P);if (bf == 1){S->_bf = -1;P->_bf = 0;}else if (bf == -1){S->_bf = 0;P->_bf = 1;}else if (bf == 0){S->_bf = P->_bf = 0;}G->_bf = 0;}void RotateRL(Node<T>* cur) // 右左双旋{Node<T>* P = cur;Node<T>* S = P->_right;Node<T>* G = S->_left;short bf = G->_bf;RotateR(S);RotateL(P);if (bf == 1){S->_bf = 0;P->_bf = -1;}else if (bf == -1){S->_bf = 1;P->_bf = 0;}else if (bf == 0){S->_bf = P->_bf = 0;}G->_bf = 0;}

        用以上接口替换Rotate中的对应代码即可。

Gitee:AVL树 · 转调/C++ - 码云 - 开源中国 

第六章:总结

        单旋时,向左会被旋转到向右,向右会被旋转到向左,但是a、b、c的顺序不变

        双旋时,两种双旋的结果一样,a、b、c、d的顺序也不变,而且双旋可以拆分成两次单旋:S先旋、P后旋。 

        负二左负右单旋,反之正一左右旋;正二右正左单旋,反之负一右左旋;两个双旋子先动;a、b、c、d顺序齐。 

下期预告:

        第十三章将介绍另外一种搜索二叉树——红黑树。

http://www.dtcms.com/wzjs/332576.html

相关文章:

  • 如何在网站上做推广网络软文怎么写
  • 熟练做网站需要了解什么搜易网服务介绍
  • 中学加强校园网站内容建设seowhy培训
  • 建设银行网站不足和建议廊坊网络推广优化公司
  • 站长工具seo综合查询怎么用东莞网络营销推广公司
  • 天津企业网站策划公司如何做seo优化
  • 有谁用2008做网站服务器兰州网络推广推广机构
  • 中国菲律宾世预赛aso搜索排名优化
  • 石排网站仿做百度网站收录入口
  • 做网站的教程北京首页关键词优化
  • wordpress怎么进入编辑模式网站整站优化推广方案
  • 免费申请域名建立网站东莞做网站的公司有哪些
  • 房产做网站吸引经典软文广告案例
  • 怎样建网站得花多少钱网络营销策略实施的步骤
  • 网站建设评审会总结发言山东网站建设
  • 深圳手机商城网站设计东莞seo建站公司
  • 资阳seo优化公司seo网站课程
  • 仪器仪表公司网站模版网址之家大全
  • 网络营销方式使用情况数据seo网络推广到底是做什么的
  • 大学生简历制作网站宁波seo网络推广报价
  • 企业展示类网站模板深圳网络优化公司
  • 电子商务网站建设与管理课后第四章浙江网站推广公司
  • 做app网站需要什么技术支持八宿县网站seo优化排名
  • 网站可以先做后再申请域名吗在线网站seo优化
  • 优质的南昌网站建设优化推广方案
  • 郴州宸轩网络科技有限公司网站搜索优化价格
  • 咸宁商城网站建设seo在线培训机构
  • 织梦dede建站教程视频搜索引擎优化指的是
  • 安徽专业网站建设大全推荐百度网盘在线登录入口
  • 电子商务网站建设如何google代理