平衡二叉查找树插入节点操作( AVLTree ):旋转、调整平衡

AVL树的插入

在向一棵本来高度平衡的AVL树中插入一个新节点时,如果树中某个结点的平衡因子的绝对值 > 1,则出现了不平衡。设新插入结点为P,从结点P到根节点的路径上,每个结点为根的子树的高度都可能增加1,因此在每执行一次二叉搜索树的插入运算后,都需从新插入的结点P开始,沿该结点插入的路径向根节点方向回溯,修改各结点的平衡因子,调整整棵树的高度,恢复被破坏的平衡性质。

 

AVL树插入算法:

 

新节点P的平衡因子为0,但其双亲结点Pr的平衡因子有三种情况:

 

1、结点Pr的平衡因子为0

在Pr的较矮的子树上插入新节点,结点Pr平衡,其高度没有增加,此时从Pr到根路径上各结点为根的子树的高度不变,即各结点的平衡因子不变,结束平衡化处理。

 

2、结点Pr的平衡因子的绝对值为1;

插入前Pr的平衡因子为0,插入后以Pr为根的子树没有失去平衡,但该子树的高度增

加,需从该结点Pr向根节点方向回溯,继续查看Pr的双亲结点的平衡性。

 

3、结点Pr的平衡因子的绝对值为2

新节点在较高的子树插入,需要做平衡化处理:

若Pr = 2,说明右子树高,设Pr的右子树为q

当q的平衡因子为1,执行左单旋转

 

 

 

 

当q的平衡因子为-1,执行先右后左双旋转

 

 

 

若Pr = -2,说明左子树高,设Pr的左子树为q

当q的平衡因子为-1,执行右单旋转

 

当q的平衡因子为1,执行先左后右双旋转

 


具体代码:

#include<iostream>  

using namespace std;



template<class K, class V>

struct AVLTreeNode

{

AVLTreeNode<K, V>* _pleft;

AVLTreeNode<K, V>* _pright;

AVLTreeNode<K, V>* _pParent;

K _key;

V _value;

int _bf;

AVLTreeNode(const K& key, const V& value)

:_pleft(NULL)

, _pright(NULL)

,_pParent(NULL)

, _key(key)

,_value(value)

,_bf(0)

{}

};



template<class K, class V>

class AVLTree

{

typedef AVLTreeNode<K, V> Node;



public:

AVLTree()

:_pRoot(NULL)

{}

AVLTree(const AVLTree<K, V>& t);

AVLTree<K, V>& operator=(const AVLTree<K, V>& t);



~AVLTree()

{

_Destory(_pRoot);

}



public:

bool Insert(const K& key, const V& value)

{

if(NULL == _pRoot)

{

_pRoot = new Node(key, value);

return true;

}



//寻找插入位置

Node* parent = NULL;

Node* pCur = _pRoot;

while(pCur)

{

if(key < pCur->_key)

{

parent = pCur;

pCur = pCur->_pleft;

}

else if(key > pCur->_key)

{

parent = pCur;

pCur = pCur->_pright;

}

else

return false;

}

pCur = new Node(key, value);

//插入

if(key < parent->_key)

{

parent->_pleft = pCur;

}

else

{

parent->_pright = pCur;

}

pCur->_pParent = parent;



//更新平衡因子

while(parent)

{

if(parent->_pleft == pCur)

{

parent->_bf--;

}

else

{

parent->_bf++;

}



if(parent->_bf == 0)

{

break;

}

else if(1 == parent->_bf || parent->_bf == -1)

{

pCur = parent;

parent = pCur->_pParent;

}

else

{

if(parent->_bf == 2)

{

if(pCur->_bf == 1)

_RotateL(parent);

else if(pCur->_bf == -1)

_RotateRL(parent);

}

else if(parent->_bf == -2)

{

if(pCur->_bf == -1)

_RotateR(parent);

else if(pCur->_bf == 1)

_RotateLR(parent);

}

break;

}

}

return true;

}

void Inorder()     //中序遍历

{

_Inorder(_pRoot);

cout << endl;

}

bool IsBalance()    //判断是否平衡

{

int height = 0;

return _IsBalance(_pRoot, height);

}





private:

void _RotateR(Node* parent)

{

Node* subL = parent->_pleft;

Node* subLR = subL->_pright;

parent->_pleft = subLR;

if(subLR)

subLR->_pParent = parent;

subL->_pright = parent;

Node* pParent = parent->_pParent;

parent->_pParent = subL;

if(pParent == NULL)

{

_pRoot = subL;

subL->_pParent = NULL;

}

else

{

if(pParent->_pleft == parent)

{

pParent->_pleft = subL;

}



else

{

pParent->_pright = subL;

}

subL->_pParent = pParent;

}

subL->_bf = parent->_bf = 0;

}



void _RotateL(Node* parent)

{

Node* subR = parent->_pright;

Node* subRL = subR->_pleft;

parent->_pright = subRL;

if(subRL)

subRL->_pParent = parent;

subR->_pleft = parent;

Node* pParent = parent->_pParent;

parent->_pParent = subR;

if(pParent == NULL)

{

_pRoot = subR;

subR->_pParent = NULL;

}

else

{

if(pParent->_pleft == parent)

{

pParent->_pleft = subR;

}

else

{

pParent->_pright = subR;

}

subR->_pParent = pParent;

}

subR->_bf = parent->_bf = 0;

}



void _RotateRL(Node*& parent)

{

        Node* subR = parent->_pright;  

        Node* subRL = subR->_pleft;  

        _RotateR(subR);      

        _RotateL(parent);       

  

        int bf = subRL->_bf;  

  

        if (bf == 0)  

        {    

            subRL->_bf = parent->_bf = subR->_bf = 0; 

        }  

  

        else if (bf == -1)  

        {  

            subRL->_bf = 0;  

            parent->_bf = 1;  

            subR->_bf = 0;  

        }  

  

        else if (bf == 1)  

        {  

            subRL->_bf = 0;  

            parent->_bf = 0;  

            subR->_bf = 1;  

        } 

}

void _RotateLR(Node*& parent)

{

        Node* subL = parent->_pleft;  

        Node* subLR = subL->_pright;  

        _RotateL(subL);  

        _RotateR(parent);  

        int bf = subLR->_bf;  

  

        if (bf == 0)  

        {  

            subLR->_bf = parent->_bf = subL->_bf = 0;  

        }  

  

        else if (bf == 1)  

        {  

            subLR->_bf = 0;  

            parent->_bf = 1;  

            subL->_bf = 0;  

        }  

  

        else if (bf == -1)  

        {  

            subLR->_bf = 0;  

            parent->_bf = 0;  

            subL->_bf = -1;  

        }  

}



void _Destory(Node*& pRoot)

{

if (_pRoot == NULL)

return;

_Destory(pRoot->_pleft);

_Destory(pRoot->_pright);

delete pRoot;

pRoot = NULL;

}



protected:

void _Inorder(Node* pRoot)     //中序

{

if (pRoot == NULL)

{

return;

}



_Inorder(pRoot->_pleft);

cout << pRoot->_key << " ";

_Inorder(pRoot->_pright);

}



bool _IsBalance(Node* pRoot, int& height)

{

if (pRoot == NULL)

{

height = 0;

return true;

}



int left, right;

if (_IsBalance(pRoot->_pleft, left) && _IsBalance



(pRoot->_pright, right)

&& abs(right - left) < 2)

{

height = left > right ? left + 1 : right + 1;



if (pRoot->_bf != right - left)

{

cout << "平衡因子异常:" << pRoot->_key 



<< endl;

return false;

}



return true;

}

else

{

return false;

}

}



size_t _Height(Node* pRoot)    //高度

{

if (pRoot == NULL)

{

return 0;

}

int l = _Height(pRoot->_pleft);

int r = _Height(pRoot->_pright);



return l > r ? l + 1 : r + 1;

}



private:

Node* _pRoot;

};



int main()

{

AVLTree<int, int> t;

t.Insert(3,3);

t.Insert(7,7);

t.Insert(11,11);

t.Insert(14,14);

t.Insert(15,15);

t.Insert(18,18);

t.Insert(16,16);

t.Insert(26,26);

t.Insert(9,9);

t.Inorder();  

    cout << "IsBalance? " << t.IsBalance() << endl;  



system("pause");

return 0;

}
















本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/459429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fork/Join框架介绍

转http://www.infoq.com/cn/articles/fork-join-introduction/ 1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架&#xff0c; 是一个把大任务分割成若干个小任务&#xff0c;最终汇总每个小任务结果后得到大任务结果的框架。 我们再通过Fork和…

为什么析构函数可以能声明为虚函数,构造函数不可以

转自&#xff1a;http://blog.csdn.NET/chen825919148/article/details/8020550 构造函数不能声明为虚函数&#xff0c;析构函数可以声明为虚函数&#xff0c;而且有时是必须声明为虚函数。 不建议在构造函数和析构函数里面调用虚函数。 构造函数不能声明为虚函数的原因是: 1 …

信号集操作函数,信号未决、阻塞、递达

转载&#xff1a;信号集操作函数&#xff0c;信号阻塞与未决 一&#xff0c;信号集及相关操作函数 信号集被定义为一种数据类型&#xff1a; typedef struct { unsigned long sig[_NSIG_WORDS]&#xff1b; } sigset_t 信号集用来描述信号的集合&#xff0c;每个信号占用一位&a…

线程安全和可重入函数的联系与区别

1、 线程安全&#xff1a; 线程安全是多线程访问时&#xff0c;采用了加锁机制&#xff0c;当一个线程访问该类的某个数据时&#xff0c;进行保护&#xff0c;其他线程不能进行访问直到该线程访问完&#xff0c;其他线程才可以使用。不会出现数据不一致或数据污染。 线程不…

C++11 多线程 基础

C11开始支持多线程编程&#xff0c;之前多线程编程都需要系统的支持&#xff0c;在不同的系统下创建线程需要不同的API如pthread_create()&#xff0c;Createthread()&#xff0c;beginthread()等&#xff0c;使用起来都比较复杂&#xff0c;C11提供了新头文件<thread>、…

LB负载均衡集群--LVS

LB集群&#xff1a;LB集群是load balance 集群的简写&#xff0c;翻译成中文就是负载均衡集群。常用的负载均衡开源软件有nginx、lvs、keepalived &#xff0c;商业的硬件负载设备F5、Netscale。LB集群架构&#xff1a;当用户的请求过来时&#xff0c;会直接发到分发器&#xf…

2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索

邱老师降临小行星 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/61Description 人赢邱老师和任何男生比&#xff0c;都是不虚的。有一天&#xff0c;邱老师带妹子(们)来到了一个N行M列平面的小行星。对于每一个着陆地点&#xf…

优化表的数据类型

我们可以使用PROCEDURE ANALYSE()对当前已有应用的表类型的判断&#xff0c;该函数可以对数据表中的列的数据类型提出优化建议&#xff0c;可以根据应用的实际情况酌情考虑是否实施优化。语法&#xff1a; SELECT * FROM tbl_name PROCEDURE ANALYSE(); SELECT * FROM tb…

Linux 信号之mysleep

一、 用alarm和pause实现sleep(3)函数,称为mysleep。 1. main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数sig_alrm。 2. 调用alarm(seconds)设定闹钟。 3. 调用pause等待,内核切换到别的进程运行。 4. seconds秒之后,闹钟超时,内核发SIGALRM给这个…

JAVA 操作系统已经来到第五个版本了 现陆续放出三个版本 这是第二个版本

1 package System2;2 3 import javax.swing.*;4 5 import java.awt.*;6 import java.awt.event.ActionEvent;7 import java.awt.event.ActionListener;8 import java.awt.event.KeyListener;9 import java.util.*;10 /**11 * 作者:范铭祥12 * 内容及功能&#xff1a; 显示框…

标准Web系统的架构分层

1、架构体系分层图 在上图中我们描述了Web系统架构中的组成部分。并且给出了每一层常用的技术组件/服务实现。需要注意以下几点&#xff1a; 系统架构是灵活的&#xff0c;根据需求的不同&#xff0c;不一定每一层的技术都需要使用。例如&#xff1a;一些简单的CRM系统可能在产…

数据链路层差错检测:CRC(循环冗余检验)

1、循环冗余检验&#xff08;CRC&#xff09;&#xff1a; 在发送端&#xff0c;先把数据划分为祖&#xff0c;假定每组K个比特。现假定待传送的数据M 101001&#xff08;k6&#xff09;。CRC运算就是在数据M后面添加提供差错检测的n位冗余码&#xff0c;然后构成一个帧发送出…

算法导论笔记:25所有节点对的最短路径问题

本章考虑在给定的有向加权图G(V, E)&#xff0c;对于所有的节点u,v∈V&#xff0c;找到一条从节点u到节点v的最短路径。希望以表格的形式表示输出&#xff1a;第u行第v列给出的是节点u到节点v的最短路径权重。 对于这个问题&#xff0c;如果是运行|V|次单源最短路径算法来解决所…

iOS开发~UI布局(二)storyboard中autolayout和size class的使用详解

一、概要&#xff1a;前一篇初步的描述了size class的概念&#xff0c;那么实际中如何使用呢&#xff0c;下面两个问题是我们一定会遇到的&#xff1a;1、Xcode6中增加了size class&#xff0c;在storyboard中如何使用&#xff1f; 2、auto layout该如何与size class配合来进行…

Linux:守护进程解析、如何实现守护进程

1、守护进程&#xff1a; 守护进程也称精灵进程&#xff08;Daemon&#xff09;&#xff0c;是运行在后台的⼀一种特殊进程。它独立于控制终端且周期性地执行某种任务或等待处理某些发生的事件。守护进程是⼀一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如…

CAS实现单点登录方案(SSO完整版)

一、简介 1、cas是由耶鲁大学研发的单点登录服务器 2、本教材所用环境 Tomcat7.2JDK1.7CAS Service 版本 cas-server-3.4.8-releaseCAS Client版本 cas-client-3.2.1-release 二、生成证书 证书对于实现此单点登录非常之重要&#xff0…

PHP、C#、通用的DES加密

2019独角兽企业重金招聘Python工程师标准>>> PHP class JoDES {private static $_instance NULL;/*** return JoDES*/public static function share() {if (is_null(self::$_instance)) {self::$_instance new JoDES();}return self::$_instance;}/*** 加密* para…

如何防止头文件被重复包含或引用?

一、#pragma once ( 比较常用&#xff09; 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次&#xff0c;这条指令实际上在VC6中就已经有了&#xff0c;但是考虑到兼容性并没有太多的使用。 #pragmaonce是编译相关&#xff0c;就是说这个编译系统上能用&#xff…

如何解决类模板的分离编译问题?

一模板&#xff1a; 模板不是数据类型&#xff0c;只能算是一种行为集合的表示。编译器在使用模板时&#xff0c;通过更换模板参数来创建数据类型。这个过程就是模板实例化(Instantiation)&#xff0c; 从模板类创建得到的类型称之为特例(specialization)&#xff0c;说白了就是…

结对项目 刘静 201303014059 计科高职13-2

结对&#xff1a;人&#xff1a;孙帅 博客地址&#xff1a; http://www.cnblogs.com/s3366181/p/4509260.html一、 题目简介 1.所选题目&#xff1a;输出圆的面积 2.编程工具&#xff1a;Eclipse 3、实现功能&#xff1a;用户给定一圆的半径运行程序系统会给出给定半径圆的面…