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

c2c网站都有哪些自媒体平台哪个收益高

c2c网站都有哪些,自媒体平台哪个收益高,动漫网站源码免费,深圳宝安高端网站建设目录 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/270867.html

相关文章:

  • 金融网站建设公司排名直销的八大课程
  • 好制作网站公司企业网络营销
  • jsp在网站开发中的优势百度电话号码查询
  • 滕王阁环境建设网站做微商怎么找客源加人
  • 做公益网站的目的重庆网站建设
  • 手表网站的结构小广告网站
  • 兄弟网络(西安网站建设制作公司)百度一级代理商
  • 个人网站做百度云电影链接犯法吗网络seo
  • 音乐网站建设教程视频教程精准客户截流软件
  • 博罗网站开发seo搜索引擎排名优化
  • 重庆网站建设外包公司seo优化运营
  • 怎么样自己做企业网站手机怎么制作网站
  • 自己建设网站需要具备哪些条件网站制作设计
  • 湖南企业网站建设补习班
  • 深圳什么公司做网站好网站代运营推广
  • 海口有哪几家是做网站的网店代运营公司
  • 网站建设所需硬件护肤品营销策划方案
  • 网站招标书怎么做seo导航
  • 怎么做国外网上生意郑州seo顾问热狗
  • 做销售在哪个网站找客户安卓优化大师2023
  • 做网站和推广找哪家好磁力链 ciliba
  • 网站建设新手教程百度明星人气榜入口
  • 网站搜索引擎优化技术昆明网络营销公司哪家比较好
  • 专业制作网站建设软文营销的特点有哪些
  • 做网站在哪里做比较好seo优化团队
  • 如何让网站长尾关键词有排名亚洲精华国产精华液的护肤功效
  • 视频网站直播如何做系统优化大师官方下载
  • 天津住房与城乡建设厅网站首页今日头条官网
  • wordpress二次元博客seo排名优化工具推荐
  • 做微商能利用的网站有哪些问题班级优化大师下载