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

软件技术属于什么学类网站优化招商

软件技术属于什么学类,网站优化招商,四川营销型网站建设,做淘宝详情的网站目录 1.AVL树的概念 2.AVL树的实现 2.1 AVL树节点的定义 2.2 AVL树的插入结构 2.3 AVL树的旋转 2.3.1 左单旋 2.3.2 右单旋 2.3.3 右左双旋 2.3.4 左右双旋 2.4 总体的插入逻辑 1.AVL树的概念 二叉搜索树虽可以增加查找的效率,但如果数据有序或接近有序&…

目录

1.AVL树的概念

2.AVL树的实现

2.1 AVL树节点的定义

2.2 AVL树的插入结构

2.3 AVL树的旋转

 2.3.1 左单旋

2.3.2 右单旋

2.3.3 右左双旋

2.3.4 左右双旋

2.4 总体的插入逻辑


1.AVL树的概念

        二叉搜索树虽可以增加查找的效率,但如果数据有序或接近有序,二叉搜索树将会退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因为两位俄罗斯的数学家发明了一种解决上述问题的方法:当向二叉搜索树中插入新节点后,如果能保证每个节点的左右子树高度之差的绝对值不超过1,即可降低树的高度,从而减少平均搜索长度。

一颗AVL树或者是空树,是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL树"高度平衡二叉树"
  • 左右子树高度之差(平衡因子)的绝对值不超过1(-1、0、1)

|右子树高度-左子树高度|≤1,平衡为什么不是高度相等呢?有时候是真的做不到。

2.AVL树的实现

2.1 AVL树节点的定义

template<class K, class V>
struct AVLTreeNode
{pair<K, V> _kv;AVLTreeNode<K, V> *left;AVLTreeNode<K, V> *right;AVLTreeNode<K, V> *parent;int _bf;explicit AVLTreeNode(const pair<K, V>& kv): _kv(kv), left(nullptr), right(nullptr), parent(nullptr), _bf(0){}
};

2.2 AVL树的插入结构

template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V> Node;
public:bool insert(const pair<K, V>& kv){if(_root == nullptr){_root = new Node(kv);return true;}Node* cur = _root;Node* parent = nullptr;while(cur){if(kv.first < cur->_kv.first){parent = cur;cur = cur->left;}else if(kv.first > cur->_kv.first){parent = cur;cur = cur->right;}elsereturn false;}cur = new Node(kv);if(kv.first < parent->_kv.first)parent->left = cur;elseparent->right = cur;cur->_parent = parent;//控制平衡,更新平衡因子_bf}
private:Node* _root = nullptr;
};

上面是插入了结点,下面就该考虑如何平衡了:需要分情况讨论:

插入结点就会改变 cur 的 _parent 的 _bf:

新增在左:parent 的因子 --

  20(-1)/  
10(0)

新增在右:parent 的因子 ++

20(1)\30(0)

更新后 parent 的因子 == 0,parent的子树高度不变,不会影响祖先,不再向上更新

  20(0)/  \
10   30

更新后 parent 因子 == 1 or -1,说明parent的平衡因子原来是0,现在高度变了,需要沿parent逐级向上更新,因为当前树变的不平衡,一定会影响更高层的_bf,也就是根据parent的变化,更新parent->_parent的 _bf

  20 (0)/  \
10   30(1) parent\40 cur

 向上更新时,相当于cur新增在下面这个parent的右边,所以 parent 的 _bf --,由0变-1

  20 parent (0)->(-1)/  \
10   30(1) cur\40

更新后 parent 因子 == 2 or -2,说明 parent 原来就不平衡,此时更不平衡了,需要对parent所在子树进行旋转

  20 (2)/  \
10   30 (2) parent\40 (1) cur\50

 更新到 cur 为根结点,也就是 parent 为 nullptr 时结束,说明更新到了最祖宗的结点

        //控制平衡,更新平衡因子_bfwhile(parent){if(cur == parent->left)parent->_bf--;elseparent->_bf++;//检查更新后的_bfif(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){//旋转}else//万一不小心更新出了3,4,5...说明2的时候就出错了assert(false);}

2.3 AVL树的旋转

        插入函数的结构我们很清楚了,下面来分析一下旋转的具体过程:

旋转的时候要注意两个问题:

  1. 保持树是搜索树
  2. 变成平衡树的同时降低树的高度
 2.3.1 左单旋

 新结点插入较高右子树的右侧-右右:左单旋

  20 /  \
10   30 (2) parent\40 (1) cur\50

核心操作:

parent->right = cur->left;
cur->left = parent;
     30 (2) parent\40 (1) cur\50parent->right = cur->left;(parent)30   40 cur\  /  \null   50cur->left = parent;40 cur/  \(parent)30  50\null

但是这时是有问题的,每个结点有三个方向,left, right, parent。

我们断开的是parent→right; cur→left, 但是只有这两步是不行的,他们之间复杂的指向关系还需要更新。

我们可以画个图:

所以我们的两个核心操作改变了三个结点之间的指向,cur、parent、cur→left

    void rotateL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if(curleft)curleft->_parent = parent;cur->_left = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if(parent == _root)//如果旋转放下去的是根结点,那么cur就是新根,它的父结点就是nullptr{_root = cur;cur->_parent = nullptr;}else//如果parent之上还有结点,那么需要在前面修改parent的_parent之前保存ppnode,现在cur->_parent=ppnode{cur->_parent = ppnode;//然后我们还不知道ppnode的left还是right链接的parent,所以也不知道是left还是right链接curif(ppnode->_left == parent)ppnode->_left = cur;elseppnode->_right = cur;}parent->_bf = cur->_bf = 0;}
  • parent为根结点,放到cur的left了,cur成为新的根节点,cur→_parent = nullptr
  • parent之上还有父节点ppnode,ppnode需要连接子树新的根节点cur,就需要判断ppnode的左还是右去连接cur。
  • 最后更新parent 和 cur 的_bf
2.3.2 右单旋

新结点添加在较高左子树的左侧-左左:右单旋

和左单旋类似,基本就是翻转过来,核心操作为:

parent->_left = cur->_right;
cur->_right = parent;
void rotateR(Node* parent)
{Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if(curright)curright->_parent = parent;cur->_right = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if(_root == parent){_root = cur;cur->_parent = nullptr;}else{cur->_parent = ppnode;if(ppnode->_left == parent)ppnode->_left = cur;elseppnode->_right = cur;}parent->_bf = cur->_bf = 0;
}
2.3.3 右左双旋

新增结点在较高右子树的左边:右左

  20 (1) /  \
10   30 /  \25   40 20 (2) /  \
10   30 (-1)/  \25   40 /24

若像原来,右子树高,parent 的 _bf = 2,走左单旋:

  20 (2) parent/  \
10   30 (-1) cur/  \25   40 /2420   30 cur/  \  /  \10   25   40 /2430/  \20   40/  \   10   25  /24

还是不平衡,所以要先对cur子树进行右单旋,再对parent进行左单旋,即为双旋:

我们看黄线就可以明显的观察出双旋的本质

第一个旋转是将 折线 变 直线,第二个旋转是将 直线 变 平衡。

void RotateRL(Node* parent)
{RotateR(parent->right);RotateL(parent);
}

但是在双旋中,因为我们调用的单旋最后都是平衡的,所以cur,curleft,parent 的 _bf 最后都修改为了0,在上图中我们可以看出这是不对的。

我们需要分情况讨论_bf的情况。

上例中我们在 60 的左边插入了新结点 40 导致的双旋,所以 60 的_bf 为-1,这种情况下,双旋完成后

cur->_bf = 1;
curleft->_bf = 0;
parent->_bf = 0;

如果在 60 的右插入新结点 50 导致双旋,那么 60 的_bf 为 1,这种情况下:

cur->_bf = 0;
curleft->_bf = 0;
parent->_bf = -1;

最后就是 60自己 引发的双旋,60 的_bf 是0,这种情况比较简单,旋转之后三个结点的平衡因子都是0

30       30\       \90  →   60  →   60/        \     /  \60        90   30  90
    void rotateRL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;int bf = curleft->_bf;rotateR(parent->_right);rotateL(parent);if(bf == 1){curleft->_bf = 0;parent->_bf = -1;cur->_bf = 0;}else if(bf == -1){curleft->_bf = 0;parent->_bf = 0;cur->_bf = 1;}else{curleft->_bf = parent->_bf = cur->_bf = 0;}}
2.3.4 左右双旋

新增结点在较高左子树的右边,与有左旋是大致相同的,基本镜像

    void rotateLR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;int bf = curright->_bf;rotateL(parent->_left);rotateR(parent);if(bf == 1){curright->_bf = 0;parent->_bf = 0;cur->_bf = -1;}else if(bf == -1){curright->_bf = 0;parent->_bf = 1;cur->_bf = 0;}else{curright->_bf = parent->_bf = cur->_bf = 0;}}

2.4 总体的插入逻辑

    bool insert(const pair<K, V>& kv){if(_root == nullptr){_root = new Node(kv);return true;}Node* cur = _root;Node* parent = nullptr;while(cur){if(kv.first < cur->_kv.first){parent = cur;cur = cur->left;}else if(kv.first > cur->_kv.first){parent = cur;cur = cur->right;}elsereturn false;}cur = new Node(kv);if(kv.first < parent->_kv.first)parent->left = cur;elseparent->right = cur;cur->_parent = parent;//控制平衡,更新平衡因子_bfwhile(parent){if(cur == parent->left)--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){if(cur->_bf == 1)rotateL(parent);elserotateRL(parent);}else{if(cur->_bf == -1)rotateR(parent);elserotateLR(parent);}break;}elseassert(false);}}
http://www.dtcms.com/wzjs/35170.html

相关文章:

  • 杭州网站制作专业河南制作网站
  • 用现成的php模板 怎么做网站seo和sem是什么意思啊
  • 做网站好学吗建一个网站大概需要多少钱
  • 怎么给网站做友情链接怎么做一个自己的网页
  • 一级a做片免费网站种子资源
  • 北京做网站多少钱蚌埠网络推广
  • 高端网站建设kgu百度竞价排名医院事件
  • 第一次开票网站建设怎么开怎么在百度上面打广告
  • 中国南昌网站建设百度如何注册公司网站
  • 使用局域网做网站企业qq邮箱
  • php能做手机网站吗网站seo入门基础教程
  • 网站服务合同范本高质量外链购买
  • 做购物网站学什么技术推广和竞价代运营
  • 河南省做网站的公司有哪些ip域名解析查询
  • 做门户网站那个系统好站长权重
  • 做网站可以用什么软件交换神器
  • 长春网站制作教程seo是哪个英文的缩写
  • 网站1g空间多大搜索引擎seo
  • 网站建设公司广告比百度好用的搜索软件
  • 网站开发背景论文长沙网站关键词排名推广公司
  • 如何做国外外贸网站有什么推广产品的渠道
  • 设计方面的网站网站推广seo教程
  • 代码编辑器做热点什么网站好扬州网络推广哪家好
  • 中国建设银行河北省分行官方网站新品推广策划方案
  • 做yield网站多少钱微信营销的方法7种
  • 德州建设局网站seo刷点击软件
  • 用wix做网站需要备案吗微信广告投放推广平台多少费用
  • 商城网站开发公司百度统计收费吗
  • 推广策略是什么优化搜索引擎的方法
  • 元做网站软件开发工程师