【C++】-- AVL树详解

目录

一、AVL树概念

1.二叉搜索树的缺点 

2.AVL树的概念 

二、AVL树定义

1.AVL树节点定义

 2.AVL树定义

三、AVL树插入 

1.插入节点

2.控制平衡 

(1)更新平衡因子

(2)旋转

         ①右单旋

         ②左单旋

         ③左右双旋

         ④右左双旋

四、AVL树查找

五、AVL树高度 

 六、判断是否为AVL树

七、AVL树遍历

八、时间复杂度


一、AVL树概念

1.二叉搜索树的缺点 

 map/multimap/set/multiset的底层都按照二叉搜索树实现,但是在【C++】-- 搜索二叉树一文中已经了解到二叉搜索树的缺点在于,假如向树中插入的元素有序或者接近有序时,二叉搜索树就会退化成单支树,时间复杂度会退化成O(N),相当于在顺序表中搜索元素,效率低下。所以map/multimap/set/multiset的底层结构对二叉搜索树做了处理,采用平衡树来实现。

2.AVL树的概念 

如何避免二叉树搜索树会退化成单支树的缺点呢?

向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。为什么高度差的绝对值不超过1而不是0呢?因为如果高度差的绝对值不超过0,那么二叉树就变成满二叉树了,因此绝对值不能超过1。这就引入了平衡二叉树的概念:

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

(1)它的左右子树都是AVL树
(2)左右子树高度之差(简称平衡因子=右子树高度-左子树高度)的绝对值不超过1(-1/0/1)

 如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在,搜索时
间复杂度O()。

二、AVL树定义

由于要实现AVL树的增删改查,所以定义AVL树的节点,就需要定义parent,否则插入节点时,不知道要链接到树里面哪个节点下面。

1.AVL树节点定义

节点定义:

#pragma once
#include<iostream>
using namespace std;

template<class K,class V>
class AVLTreeNode
{
	AVLTreeNode<K, V>* _left;//左子树
	AVLTreeNode<K, V>* _right;//右子树
	AVLTreeNode<K, V>* _parent;//父亲

	int _bf;//平衡因子

	pair<K, V> _kv;//节点

	AVLTreeNode(const pair<K, V>&, kv)
	{
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_bf(0)
		, _kv(kv)
	}
	{}

};

 2.AVL树定义

template<class K,class V>
struct AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
		//构造函数
	AVLTree()
		:_root(nullptr)
	{}

	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);

		delete root;
	}

    //重载operator[]
	V& operator[](const K& key)
	{
		pair<Node*, bool> ret = Insert(make_pair(key, V()));
		return ret.first->_kv.second;
	}

	//析构函数
	~AVLTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}

private:
	Node* _root;
};

三、AVL树插入 

1.插入节点

插入节点需要先判断树是否为空:

(1)若为空,让该节点作为根节点

(2)若不为空,分3种情况:

①key比当前节点小,向左走

②key比当前节点大,向右走

③相等,插入失败

如果没找到节点,那么需要插入新节点

	bool Insert(const pair<K, V>& kv)
	{
		//1.空树
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}

		//2.非空树
		Node* parent = _root, * cur = _root;
		while (cur)
		{
			if (cur->_kv.first > kv.first)//向左找
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_kv.first < kv.first)//向右找
			{
				parent = cur;
				cur = cur->_right;
			}
			else//找到了
			{
				return false;
			}
		}

		//没找到,需要插入
		cur = new Node(kv);
		if (parent->_kv.first < cur->_kv.first)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值