【数据结构】平衡二叉树

这篇具有很好参考价值的文章主要介绍了【数据结构】平衡二叉树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

平衡二叉树,数据结构与算法,数据结构,c++,STL,平衡二叉树,算法


需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。


 目录

一、平衡二叉树的介绍

二、平衡二叉树的插入

1、平衡二叉树的插入步骤

2、平衡二叉树的旋转

2.1左单旋

2.2右单旋

2.3左右双旋

2.4右左双旋

三、平衡二叉树的删除(略)

四、个人对平衡二叉树见解

五、平衡二叉树整体代码


一、平衡二叉树的介绍

        的目的是为了提高查找效率,但如果数据有序或者接近有序,那么二叉搜索树将会变成单支树,查找元素的效率等效为顺序表,树形结构的优势荡然无存。

        为了解决这一问题,苏联数学家G.M.Adelson-Velskii和E.M.Landis便发明了平衡二叉树(AVL树)。

        平衡二叉树:在一棵搜索二叉树中每个节点的左右子树的高度差的绝对值不超过1。左右子树的高度差被称为平衡因子(平衡因子=右子树高度-左子树高度)若一颗平衡二叉树的节点个数为n,那么其高度为logN。

二、平衡二叉树的插入

1、平衡二叉树的插入步骤

        平衡二叉树的插入第一步和二叉搜索树一样,根据二叉搜索树的特性,找到新插入节点位于整棵树的位置。

        随后使用逻辑语句判断新节点是插入在父节点的左还是右,并维护其与父节点的指针关系。

        新增在右,平衡因子++;新增在左,平衡因子--。那新插入了一个节点,原先的平衡二叉树的结构可能会遭到破坏,所以需要观察平衡因子的三种情况,进行分类讨论:如图

平衡二叉树,数据结构与算法,数据结构,c++,STL,平衡二叉树,算法

        情况三如何旋转?无非是四种情况:

平衡二叉树,数据结构与算法,数据结构,c++,STL,平衡二叉树,算法

2、平衡二叉树的旋转

        当出现上图情况三时,就需要对平衡二叉树的节点进行旋转,旋转的目的是要让这颗树继续维持平衡二叉树的形态,同时调节子树的高度,让其和插入前的高度保持一致,旋转后不要忘记更新那些被旋转的节点的平衡因子。

2.1左单旋

平衡二叉树,数据结构与算法,数据结构,c++,STL,平衡二叉树,算法

        5可能是根,也可能是某颗子树的根,分类讨论:

void RotateLeft(Node* parent)//左单旋
{
	Node* grandfather = parent->_parent;
	Node* cur = parent->_right;
	if (parent == _root)
	{
		_root = cur;
		cur->_parent = nullptr;
	}
	else
	{
		if (grandfather->_left == parent)//需要判定parent原来属于grandfather的哪一边
			grandfather->_left = cur;
		else
			grandfather->_right = cur;
		cur->_parent = grandfather;
	}
	parent->_right = cur->_left;
	if (cur->_left != nullptr)
		cur->_left->_parent = parent;
	cur->_left = parent;
	parent->_parent = cur;
	//更新平衡因子
	cur->_bf = parent->_bf = 0;
}

2.2右单旋

平衡二叉树,数据结构与算法,数据结构,c++,STL,平衡二叉树,算法

void RotateRight(Node* parent)//右单旋
{
	Node* grandfather = parent->_parent;
	Node* cur = parent->_left;
	if (parent == _root)
	{
		_root = cur;
		cur->_parent = nullptr;
	}
	else
	{
		if (grandfather->_left == parent)
		{
			grandfather->_left = cur;
			cur->_parent = grandfather;
		}
		else
		{
			grandfather->_right = cur;
			cur->_parent = grandfather;
		}
	}
	parent->_parent = cur;
	parent->_left = cur->_right;
	if (cur->_right != nullptr)
		cur->_right->_parent = parent;
	cur->_right = parent;
	//更新平衡因子
	cur->_bf = parent->_bf = 0;
}

2.3左右双旋

平衡二叉树,数据结构与算法,数据结构,c++,STL,平衡二叉树,算法

void RotateLR(Node* parent)//左右双旋
{
	Node* cur = parent->_left;
	Node* curR = cur->_right;
	int bf = curR->_bf;

	RotateLeft(parent->_left);
	RotateRight(parent);
	if (bf == -1)//curR的左树插入新节点
	{
		cur->_bf = 0;
		parent->_bf = 1;
		curR->_bf = 0;
	}
	else if (bf == 1)//curR的右树插入新节点
	{
		cur->_bf = -1;
		parent->_bf = 0;
		curR->_bf = 0;
	}
	else if (bf == 0)//curR自身为新增节点
	{
		cur->_bf = 0;
		parent->_bf = 0;
		curR->_bf = 0;
	}
	else
		assert(false);//不可能出现这种情况
}

2.4右左双旋

平衡二叉树,数据结构与算法,数据结构,c++,STL,平衡二叉树,算法

void RotateRL(Node* parent)//右左双旋
{
	Node* cur = parent->_right;
	Node* curL = cur->_left;
	int bf = curL->_bf;

	RotateRight(parent->_right);
	RotateLeft(parent);
	if (bf == -1)//curL的左树插入新节点
	{
		cur->_bf = 1;
		parent->_bf = 0;
		curR->_bf = 0;
	}
	else if (bf == 1)//curL的右树插入新节点
	{
		cur->_bf = 0;
		parent->_bf = -1;
		curR->_bf = 0;
	}
	else if (bf == 0)//curL自身为新增节点
	{
		cur->_bf = 0;
		parent->_bf = 0;
		curR->_bf = 0;
	}
	else
		assert(false);//不可能出现这种情况
}

三、平衡二叉树的删除(略)

        按照二叉搜索树的方式对平衡二叉树节点进行删除。更新平衡因子时,平衡因子为1或-1便可以停止向上更新。当平衡因子绝对值大于1时,同样需要进行旋转解决。

四、个人对平衡二叉树见解

        平衡二叉树强就强在通过大量的旋转控制整颗树任意一个节点的左右子树高度差不大于1,使树的结构近似完全二叉树,搜索效率为logN。

        但偏偏是频繁的旋转,导致其插入删除的效率并不及红黑树,这也是红黑树成为树形容器的原因。

        但是一颗树仅用来查找而不进行删除的话,用平衡二叉树还是很棒的。文章来源地址https://www.toymoban.com/news/detail-776228.html

五、平衡二叉树整体代码

#pragma once
#include <iostream>
#include <cassert>
#include <map>
#include <set>
#include <time.h>
using namespace std;

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;//Balance factor平衡因子
	AVLTreeNode(const pair<K, V>& kv)
		: _kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)
	{}
};

template <class K, class V>
struct AVLTree
{
	typedef AVLTreeNode<K, V> Node;//记住不要把这个<K,V>漏了!!!
public:
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		//_root不为空
		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;
			cur->_parent = parent;//维护cur的父指针
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		//更新平衡因子
		while (parent)//最坏情况更新到根
		{
			if (cur == parent->_left)
			{
				--parent->_bf;
			}
			else if (cur == parent->_right)
			{
				++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)//父节点的平衡因子为2或-2,不满足平衡二叉树规则
			{
				//需要旋转调整
				if (parent->_bf == 2 && cur->_bf == 1)//触发左单旋条件
				{
					RotateLeft(parent);//左单旋
				}
				else if (parent->_bf == -2 && cur->_bf == -1)//触发右单旋条件
				{
					RotateRight(parent);//右单旋
				}
				else if (parent->_bf == -2 && cur->_bf == 1)//触发左右双旋
				{
					RotateLR(parent);//左右双旋
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
					RotateRL(parent);//右左双旋
				}
				else
				{
					assert(false);
				}
				break;//必定平衡,跳出循环
			}
			else//防止出现代码错误导致平衡因子绝对值出现大于3的情况(正常情况不会发生这种现象)
			{
				assert(false);
			}
		}
		return true;
	}
	void RotateLeft(Node* parent)//左单旋
	{
		Node* grandfather = parent->_parent;
		Node* cur = parent->_right;
		if (parent == _root)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (grandfather->_left == parent)//需要判定parent原来属于grandfather的哪一边
				grandfather->_left = cur;
			else
				grandfather->_right = cur;
			cur->_parent = grandfather;
		}
		parent->_right = cur->_left;
		if (cur->_left != nullptr)
			cur->_left->_parent = parent;
		cur->_left = parent;
		parent->_parent = cur;
		//处理平衡因子
		cur->_bf = parent->_bf = 0;
	}
	void RotateRight(Node* parent)//右单旋
	{
		Node* grandfather = parent->_parent;
		Node* cur = parent->_left;
		if (parent == _root)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (grandfather->_left == parent)
			{
				grandfather->_left = cur;
				cur->_parent = grandfather;
			}
			else
			{
				grandfather->_right = cur;
				cur->_parent = grandfather;
			}
		}
		parent->_parent = cur;
		parent->_left = cur->_right;
		if (cur->_right != nullptr)
			cur->_right->_parent = parent;
		cur->_right = parent;
		//更新平衡因子
		cur->_bf = parent->_bf = 0;
	}
	void RotateLR(Node* parent)//左右双旋
	{
		Node* cur = parent->_left;
		Node* curR = cur->_right;
		int bf = curR->_bf;

		RotateLeft(parent->_left);
		RotateRight(parent);
		if (bf == -1)//curR的左树插入新节点
		{
			cur->_bf = 0;
			parent->_bf = 1;
			curR->_bf = 0;
		}
		else if (bf == 1)//curR的右树插入新节点
		{
			cur->_bf = -1;
			parent->_bf = 0;
			curR->_bf = 0;
		}
		else if (bf == 0)//curR自身为新增节点
		{
			cur->_bf = 0;
			parent->_bf = 0;
			curR->_bf = 0;
		}
		else
			assert(false);//不可能出现这种情况
	}
	void RotateRL(Node* parent)//右左双旋
	{
		Node* cur = parent->_right;
		Node* curL = cur->_left;
		int bf = curL->_bf;

		RotateRight(parent->_right);
		RotateLeft(parent);
		if (bf == -1)//curL的左树插入新节点
		{
			cur->_bf = 1;
			parent->_bf = 0;
			curL->_bf = 0;
		}
		else if (bf == 1)//curL的右树插入新节点
		{
			cur->_bf = 0;
			parent->_bf = -1;
			curL->_bf = 0;
		}
		else if (bf == 0)//curL自身为新增节点
		{
			cur->_bf = 0;
			parent->_bf = 0;
			curL->_bf = 0;
		}
		else
			assert(false);//不可能出现这种情况
	}
	
	int TreeHight(Node* root)
	{
		if (root == nullptr)
			return 0;
		int leftHight = TreeHight(root->_left);
		int rightHight = TreeHight(root->_right);
		return leftHight > rightHight ? leftHight + 1 : rightHight + 1;
	}
	void Inorder()
	{
		_Inorder(_root);
	}
	bool IsBalance()
	{
		return _IsBalance(_root);
	}
private:
	void _Inorder(Node* root)
	{
		if (root == nullptr)
			return;

		_Inorder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_Inorder(root->_right);
	}
	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
			return true;
		int leftHight = TreeHight(root->_left);
		int rightHight = TreeHight(root->_right);
		//检查平衡因子对不对
		if (rightHight - leftHight != root->_bf)
		{
			cout << "平衡因子出现异常" << endl;
			return false;
		}
		//需要递归检查是否平衡
		return (leftHight - rightHight <= 1 && leftHight - rightHight >= -1)
			&& _IsBalance(root->_left) && _IsBalance(root->_right);
	}
private:
	Node* _root = nullptr;
};
//void TestAVLTree()
//{
//	//int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
//	//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
//	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
//	//int a[] = { 9,8,7,6,5,4,3,2,1};
//	AVLTree<int, int> t;
//	for (auto e : a)
//	{
//		t.Insert(make_pair(e, e));
//	}
//
//	t.Inorder();
//
//	cout << t.IsBalance() << endl;
//}
void TestAVLTree()
{
	srand((unsigned int)time(0));
	const size_t N = 1000000;
	AVLTree<int, int> t;
	for (size_t i = 0; i < N; ++i)
	{
		size_t x = rand();
		t.Insert(make_pair(x, x));
		//cout << t.IsBalance() << endl;
	}

	t.Inorder();

	cout << t.IsBalance() << endl;
}

到了这里,关于【数据结构】平衡二叉树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构之二叉树和平衡二叉树

    1、二叉树: 2、平衡二叉树:

    2024年04月17日
    浏览(44)
  • 数据结构之平衡二叉树的平衡调整

    1:LL型调整 2:RR型调整 3:LR型调整 4:RL型调整 5:总结 作者约定:将导致不平衡的结点称作 被破坏者 ,破坏了结点的平衡的结点成为 破坏者 ,经过调整可以让该树平衡的结点称为 调整结点 。 LL型不平衡调整方法:以调整结点为中心,进行右旋操作,就可以使树平衡。

    2024年02月09日
    浏览(47)
  • 数据结构之平衡二叉树详解

    平衡二叉树(balanced binary tree) 又称AVL树(Adelson-Velskii and Landis) 一棵平衡二叉树或者是空树,或者是具有下列性质的 二叉排序树 :         1,左子树与右子树的高度之差的绝对值小于等于1;         2,左子树和右子树也是平衡二叉排序树. 为了方便起见,给每

    2024年02月03日
    浏览(41)
  • 【数据结构】二叉排序树——平衡二叉树的调整

    参考视频: 懒猫老师-数据结构-(59)平衡二叉树【互动视频】 (1)什么是平衡二叉树 平衡二叉树(Balanced Binary Tree)是一种特殊的二叉查找树,它的目的是保持树的高度尽量平衡,以保证查找、插入、删除等操作的时间复杂度为 O(log n)。 常见的平衡二叉树算法包括 AVL 树、红

    2024年02月04日
    浏览(40)
  • 数据结构——常见二叉树的分类(完全二叉树、满二叉树、平衡二叉树、二叉搜索树、红黑树)

    专业术语 中文 描述 Root 根节点 一棵树的顶点 Child 孩子结点 一个结点含有的子树的根节点称为该结点的子节点 Leaf 叶子结点 没有孩子的节点 Degree 度 一个节点包含子树的数量 Edge 边 一个节点与另外一个节点的连接 Depth 深度 根节点到这个节点经过边的数量 Height 节点高度 从

    2024年02月03日
    浏览(44)
  • 数据结构-各种树(二叉树、二叉查找树、平衡二叉树、红黑树、B树、B+树)

    概念:二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树 特点:每个

    2024年02月09日
    浏览(48)
  • Java常见的数据结构:栈、队列、数组、链表、二叉树、二叉查找树、平衡二叉树、红黑树

    数据结构是计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。 通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率 栈 队列 数组 链表 二叉树 二叉查找树 平衡二叉树 红黑树... 后进先出,先进后出 数据进入栈模型的过程称为

    2024年02月07日
    浏览(46)
  • 【数据结构】二叉查找树和平衡二叉树,以及二者的区别

    目录 1、二叉查找树 1.1、定义  1.2、查找二叉树的优点  1.2、查找二叉树的弊端 2、平衡二叉树 2.1、定义 2.2、 实现树结构平衡的方法(旋转机制) 2.2.1、左旋 2.2.2、右旋 3、总结        二叉查找树又名二叉排序树,亦称二叉搜索树。是每个结点最多有两个子树的树结构

    2024年02月20日
    浏览(50)
  • 计算机基础--->数据结构(6)【AVL树(平衡二叉树)】

    平衡二叉树是一种特殊的二叉搜索树,他的左子树与右子树的高度差不超过1。并且左右两个子树都是一颗平衡二叉树。保持平衡的特性使得平衡二叉树的查询、插入和删除操作在平均和最坏情况下的时间复杂度都是 O(logn) ,其中n是树中节点的数量。 相比于普通的二叉搜索树

    2024年02月12日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包