数据结构之——AVL树

  • AVL树

AVL树又称为高度平衡的二叉搜索树,它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度;

  • AVL树的性质
  1. 左子树和右子树的高度之差的绝对值不超过1
  2. 树中的每个左子树和右子树都是AVL树

下面实现一棵AVL树,主要实现其插入部分:

#pragma once

template <class K, class V>
struct AVLTreeNode
{
	K _key;
	V _val;
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	int _bf;//平衡因子

	AVLTreeNode(const K& key, const K& val)
		:_key(key)
		,_val(val)
		,_left(NULL)
		,_right(NULL)
		,_parent(NULL)
		,_bf(0)
	{}
};

template <class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	AVLTree()
		:_root(NULL)
	{}
	~AVLTree()
	{
		_Clear(_root);
	}

	bool Insert(const K& key, const V& val)
	{
		if(_root == NULL)//如果根结点为NULL,则创建一个结点,返回真
		{
			_root = new Node(key, val);
			return true;
		}

		Node* cur = _root;
		Node* prev = NULL;
		while(cur != NULL)//查找合适的位置插入
		{
			if(cur->_key == key)//如果结点已存在,则返回假
				return false;
			else if(cur->_key > key)//如果要插入值小于当前结点,则去左子树查找
			{
				prev = cur;
				cur = cur->_left;
			}
			else//如果插入值大于当前结点,则去右子树查找
			{
				prev = cur;
				cur = cur->_right;
			}
		}
		//循环结束,则表明找到了合适的位置,判断应插入左边还是右边
		Node* tmp = new Node(key, val);
		if(key < prev->_key)
			prev->_left = tmp;
		else
			prev->_right = tmp;
		tmp->_parent = prev;

		//插入结点之后,需要判断当前树是否满足AVL树的规则,若不满足,进行相应的调整
		while(prev != NULL)
		{
			//平衡因子为右边高度减去左边高度
			if(prev->_left == tmp)
				--(prev->_bf);
			else
				++(prev->_bf);

			if(prev->_bf == 0)//如果平衡因子为0,则一定平衡,因为可以看做是在同一层插入了一个结点,对高度并无影响
				break;
			else if(prev->_bf == 1 || prev->_bf == -1)//如果平衡因子为1/-1,则表明高度有所变化,需要继续向上调整
			{
				tmp = prev;
				prev = prev->_parent;
			}
			else//说明平衡因子的绝对值大于1,则这个时候不满足AVL树的性质,需要进行调整
			{
				if(prev->_bf == 2)
				{
					if(tmp->_bf == 1)
						_RotateL(prev);
					else
					{
						_RotateR(tmp);
						_RotateL(prev);
					}
				}
				else
				{
					if(tmp->_bf == -1)
						_RotateR(prev);
					else
					{
						_RotateL(tmp);
						_RotateR(prev);
					}
				}
				break;
			}
		}
		return true;
	}

	void InOrder()
	{
		_InOrder(_root);
		cout<<endl;
	}

protected:
	void _Clear(Node* root)
	{
		if(root != NULL)
		{
			_Clear(root->_left);
			_Clear(root->_right);
			delete root;
			root = NULL;
		}
	}

	//左单旋
	void _RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if(subRL != NULL)
			subRL->_parent = parent;
		subR->_left = parent;

		Node* ppNode = parent->_parent;
		parent->_parent = subR;

		if(ppNode == NULL)
			_root = subR;
		else
		{
			if(ppNode->_left == parent)
				ppNode->_left = subR;
			else
				ppNode->_right = subR;
		}
		subR->_parent = ppNode;
		parent->_bf = subR->_bf = 0;
	}

	//右单旋
	void _RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if(subLR != NULL)
			subLR->_parent = parent;
		subL->_right = parent;

		Node* ppNode = parent->_parent;
		parent->_parent = subL;

		if(ppNode == NULL)
			_root = subL;
		else
		{
			if(ppNode->_left == parent)
				ppNode->_left = subL;
			else
				ppNode->_right = subL;
		}
		subL->_parent = ppNode;
		parent->_bf = subL->_bf = 0;
	}

	void _InOrder(Node* root)
	{
		if(root != NULL)
		{
			_InOrder(root->_left);
			cout<<root->_key<<" ";
			_InOrder(root->_right);
		}
	}

protected:
	Node* _root;
};

void Test()
{
	int arr[] = {4, 2, 6, 1, 3, 5, 15, 7, 16, 14};
	//int arr[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};
	AVLTree<int, int> t;

	for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i)
		t.Insert(arr[i], i);

	t.InOrder();
}

其中的左右单旋如下图所示:




运行程序:

《完》

时间: 2024-10-19 05:29:50

数据结构之——AVL树的相关文章

数据结构之AVL树

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 在前面的博文中,我们已经介绍了数据结构之二分查找树的相关知识,二分查找的提出主要是为了提高数据的查找效率.同一个元素集合可以对应不同的二分查找树BST,二分查找树的形态依赖于元素的插入顺序.同时我们也已经知道,如果将一个有序的数据集依次插入到二查找树中,此时二分查找树将退化为线性表,此时查找的时间复杂度为o(n).为了防止这一问题的出现,便有了平衡二叉树的存在价值.平衡二叉树从根本上将是为了防止出现斜二叉树的出现,从而进一步提高元素的查找效率,

个人项目:数据结构之AVL树的实现

AVL树为了防止树的深度过深出现的一种数据结构,在二叉树的基础上添加了一条规则:每个节点的左子数与右子树的高度最多差1. 其中的难点之一为:插入一个节点.删除一个节点更难,在这里采用懒惰删除法.其中,在插入的时候更新根节点路径上那些节点的所有高度. AVL节点: struct AvlNode { ElementType Element; AvlTree Left; AvlTree Right; int Height; };//问题一:当插入一个节点时,如何知道哪个节点失去平衡 在插入一个节点的时

[javaSE] 数据结构(AVL树基本概念)

AVL树是高度平衡的二叉树,任何节点的两个子树的高度差别<=1 实现AVL树 定义一个AVL树,AVLTree,定义AVLTree的节点内部类AVLNode,节点包含以下特性: 1.key——关键字,对AVL树的节点进行排序 2.left——左子树 3.right——右子树 4.height——高度 如果在AVL树插入节点后可能导致AVL树失去平衡,具体会有四种状态: LL:左左,LeftLeft LR:左右,LeftRight RL:右左,RightLeft RR:右右,RightRight

[算法] 数据结构之AVL树

1 .基本概念 AVL树的复杂程度真是比二叉搜索树高了整整一个数量级——它的原理并不难弄懂,但要把它用代码实现出来还真的有点费脑筋.下面我们来看看: 1.1  AVL树是什么? AVL树本质上还是一棵二叉搜索树(因此读者可以看到我后面的代码是继承自二叉搜索树的),它的特点是: 1. 本身首先是一棵二叉搜索树. 2. 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1. 例如: 5              5 / \            / \ 2   6         

0042数据结构之AVL树

------------------------AVL树-------------------------- 自平衡树:AVL树是一颗二分搜索树,同时左右子树的高度差不超过1,AVL是自平衡的 主要是通过左旋和右旋来维护平衡 统计一本书中共出现多少个单词,每个单词出现了多少次:使用AVL树实现Set和Map,Set用于统计共出现了多少个不同的单词,Map用于容纳每个单词出现的次数. AVLTree实现如下: package avl; import java.util.ArrayList; pub

大话数据结构—平衡二叉树(AVL树)

平衡二叉树(Self-Balancing Binary Search Tree/Height-Balanced Binary Search Tree),是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1. 平衡二叉树的前提是二叉排序树,不是二叉排序树的都不是平衡二叉树. 平衡因子BF(Balance Factor):二叉树上节点的左子树深度减去右子树深度的值. 最小不平衡子树:距离插入节点最近的,且平衡因子的绝对值大于1的节点为根的子树. 下图中,新插入节点37时,距离它最近的平

数据结构与算法分析-AVL树深入探讨

.title { text-align: center; margin-bottom: .2em } .subtitle { text-align: center; font-size: medium; font-weight: bold; margin-top: 0 } .todo { font-family: monospace; color: red } .done { font-family: monospace; color: green } .priority { font-fami

AVL树C++实现

1. AVL 树本质上还是一棵二叉搜索树,它的特点是: 本身首先是一棵二叉搜索树. 带有平衡条件: 每个结点的左右子树的高度之差的绝对值(平衡因子) 最多为 1. 2. 数据结构定义 AVL树节点类: 1 template <typename T> 2 class AVLTreeNode { 3 public: 4 T key; 5 AVLTreeNode<T>* parent; 6 AVLTreeNode<T>* left; 7 AVLTreeNode<T>

数据结构与算法系列----平衡二叉树(AVL树)

一:背景 平衡二叉树(又称AVL树)是二叉查找树的一个进化体,由于二叉查找树不是严格的O(logN),所以引入一个具有平衡概念的二叉树,它的查找速度是O(logN).所以在学习平衡二叉树之前,读者需要了解二叉查找树的实现,具体链接:二叉查找树 那么平衡是什么意思?我们要求对于一棵二叉查找树 ,它的每一个节点的左右子树高度之差不超过1.(对于树的高度的约定:空节点高度是0:叶子节点高度是1.)例如下图: 如果我们的二叉查找树是不平衡该怎么办?进行旋转.经过分析发现,出现不平衡无外乎四种情况,下面我