C++数据结构之AVL树的实现

目录
  • 1.概念
    • (1)二叉搜索树的缺点
    • (2)定义节点
  • 2.插入
    • (1)拆分
    • (2)找节点与插节点
    • (3)更新平衡因子与旋转
  • 3.判断
  • 4.完整代码及测试代码
    • 完整代码
    • 测试代码

1.概念

(1)二叉搜索树的缺点

要手撕AVL树,我们首先要知道什么是AVL树。AVL树是在二叉搜索树的基础之上改造的。当我们插入的是一个有序的序列的时候,二叉搜素树会使用一条直线来进行存储,这样并不利于查找。

当遇到这种情况的时候我们就需要对这棵树来进行调整。AVL树会通过旋转等操作,来规避这种情况。最终满足每一个节点的平衡因子的绝对值<=1,从而达到近似平衡的目的。

节点的平衡因子值=右子树的高度-左子树高度

(2)定义节点

在AVL树中,除了需要定义平衡因子bf之外,还需要定义指向节点父节点的指针。方便我们来进行平衡因子的更新。

struct AVLTreeNode
{
	AVLTreeNode* right;
	AVLTreeNode* left;
	AVLTreeNode* parent;
	pair<int, int> _kv;
	int _bf;
	AVLTreeNode(pair<int, int> kv)
		:right(nullptr)
		,left(nullptr)
		,parent(nullptr)
		,_kv(kv)
		,_bf(0)
	{}
};

同时和map一样,我们使用pair类型来进行数据的存储。

2.插入

(1)拆分

AVL树的插入就是AVL树的精髓所在,我们在插入节点的同时还需要对平衡因子进行控制。

AVL树的插入我们可以拆分成五个函数,其中四个为旋转函数,一个为主要的插入函数。

而这个主要的插入函数,我们还可以将其分为三个部分:找节点,插节点,更新平衡因子。而更新平衡因子后就需要判断是否需要进行旋转的操作。

在进行插入之前,我们将插入的节点定义为kv。

(2)找节点与插节点

这一过程与二叉搜索树是相同的,这里就不多赘述了。二叉搜索树

直接上代码:

		//初始化头结点
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		//找到要插入节点的位置
		Node* cur = _root;
		Node* parent = nullptr;
		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
			{
				assert(false);
			}
		}
		//插入节点
		cur = new Node(kv);
		if (parent->_kv.first<kv.first)
		{
			parent->right = cur;
			cur->parent = parent;
		}
		else if (parent->_kv.first>kv.first)
		{
			parent->left = cur;
			cur->parent = parent;
		}
		else
		{
			assert(false);
		}

(3)更新平衡因子与旋转

更新平衡因子

每当我们插入一个节点的时候,就需要对该节点的所有父辈节点来进行平衡因子的更新。注意,当插入节点后,只有其父辈节点的平衡因子才会受到影响,而其他节点的平衡因子不会被影响。

可以根据每个节点的parent来找到其父亲节点,从而逐渐向上更新平衡因子。

当遇到以下两种情况平衡因子的更新停止。

1.某一父辈节点的平衡因子为0。

2.更新到根节点。

旋转

当更新之后的平衡因子为2或者-2的时候,不符合AVL树的平衡因子在-1~1之间的定义,此时需要发生旋转。触发旋转的条件与当前节点cur和它的parent有关。

当parent和cur的平衡因子分别为:

(1)2和1,触发左旋

	void RotateL(Node* parent)
	{
		Node* cur = parent->right;
		Node* curL = cur->left;
		Node* parentParent = parent->parent;
		parent->right = curL;
		if (curL)
			curL->parent = parent;
		cur->left = parent;
		parent->parent = cur;
		if (parent == _root)
		{
			_root = cur;
			_root->parent = nullptr;
		}
		else
		{
			if (parentParent->left == parent)
			{
				parentParent->left = cur;
				cur->parent = parentParent;
			}
			else if (parentParent->right == parent)
			{
				parentParent->right = cur;
				cur->parent = parentParent;
			}
			else
			{
				assert(false);
			}
		}
		parent->_bf = 0;
		cur->_bf = 0;
	}

用一张图来表示一下这个过程:

h表示某树的高度,当在红色部分处插入一个节点时,60的平衡因子变为1,30的平衡因子变为2。

此时就需要发生旋转:

通过旋转使树重新变成一棵AVL树,整个过程分为三步:

  • 1.60的左子树置为30,30的右子树置为60的左子树。
  • 2.将30与更上层的父辈节点链接起来。
  • 3.将30和60的平衡因子都更新为0。

注意,由于AVL树是三叉树,因此在链接的时候需要将父节点也链接起来。因此在将60的左子树链接到30的右子树的时候,需要进行判空来避免空指针的解引用:

	void RotateL(Node* parent)
	{
		Node* cur = parent->right;
		Node* curL = cur->left;
		Node* parentParent = parent->parent;
		parent->right = curL;
		if (curL)
			curL->parent = parent;
		cur->left = parent;
		parent->parent = cur;
		if (parent == _root)
		{
			_root = cur;
			_root->parent = nullptr;
		}
		else
		{
			if (parentParent->left == parent)
			{
				parentParent->left = cur;
				cur->parent = parentParent;
			}
			else if (parentParent->right == parent)
			{
				parentParent->right = cur;
				cur->parent = parentParent;
			}
			else
			{
				assert(false);
			}
		}
		parent->_bf = 0;
		cur->_bf = 0;
	}

(2)-2和-1,触发右旋

右旋同样分为三步:

  • 1.将30的右链接到60的左子树。将60链接到30的右。
  • 2.将30与上层节点链接起来。
  • 3.将30和60的平衡因子都更新为0。
	void RotateR(Node* parent)
	{
		Node* cur = parent->left;
		Node* curL = cur->left;
		Node* curR = cur->right;
		Node* parentParent = parent->parent;
		parent->left = curR;
		if (curR)
			curR->parent = parent;
		cur->right = parent;
		parent->parent = cur;
		if (parent == _root)
		{
		    _root = cur;
			_root->parent = nullptr;
		}
		else
		{
			if (parentParent->left == parent)
			{
				parentParent->left = cur;
				cur->parent = parentParent;
			}
			else if (parentParent->right == parent)
			{
				parentParent->right = cur;
				cur->parent = parentParent;
			}
			else
			{
				assert(false);
			}
		}
		cur->_bf = 0;
		parent->_bf = 0;
	}

(3)-2和1,左右双旋

当为-2和1或者2和-1的时候,仅仅靠单旋是解决不了问题的,这个时候我们就需要进行双旋:

左单旋:

右单旋:

无论是在红色部分或者蓝色部分插入节点,都会导致发生左右双旋。

左右双旋分为三步:

  • 1.对30节点进行左单旋。
  • 2.对90节点进行右单旋。
  • 3.根据60的平衡因子来更新30和90的平衡因子:当60的平衡因子为0时,30和90的平衡因子也为0;当60的平衡因子为1时,30的平衡因子为-1,90的平衡因子为0;当60的平衡因子为-1时,30的平衡因子为0,90的平衡因子为1。
	void RotateLR(Node* parent)
	{
		Node* subL = parent->left;
		Node* subLR =subL->right;
		int bf = subLR->_bf;
		RotateL(parent->left);
		RotateR(parent);
		if (bf == 0)
		{
			parent->_bf = 0;
			subLR->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = 0;
			subL->_bf = -1;
			subLR->_bf = 0;
		}
	}

(4)2和-1,右左双旋

右单旋:

左单旋:

无论是在红色部分或者蓝色部分插入节点,都会导致发生右左双旋。

右左双旋分为三步:

  • 1.对90节点进行右单旋。
  • 2.对30节点进行左单旋。
  • 3.根据60的平衡因子来更新30和90的平衡因子:当60的平衡因子为0时,30和90的平衡因子也为0;当60的平衡因子为1时,30的平衡因子为-1,90的平衡因子为0;当60的平衡因子为-1时,30的平衡因子为0,90的平衡因子为1。
	void RotateRL(Node* parent)
	{
		Node* subR = parent->right;
		Node* subRL = subR->left;
		int bf = subRL->_bf;
		RotateR(parent->right);
		RotateL(parent);
		if (bf == 0)
		{
			parent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = -1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

3.判断

我们可以建立一个函数来判断一棵树是否为AVL树。

我们使用递归来进行这一过程,依次判断各个子树是否为AVL树。

要判断我们就需要知道每一棵树的高度,此时我们需要构造一个求树的高度的函数Height。它也由递归来实现。

	int Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int leftHeight = Height(root->left);
		int rightHeight = Height(root->right);
		return rightHeight > leftHeight ? rightHeight + 1 : leftHeight + 1;
	}
	bool IsBalance()
	{
		return _IsBalance(_root);
	}
	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}
		int leftHeight = Height(root->left);
		int rightHeight = Height(root->right);
		if ((rightHeight - leftHeight) != root->_bf)
		{
			cout << "现在是:" << root->_bf << endl;
			cout << "应该是:" << rightHeight - leftHeight << endl;
			return false;
		}
		return abs(rightHeight - leftHeight) < 2 && _IsBalance(root->left) && _IsBalance(root->right);
	}

4.完整代码及测试代码

完整代码

#pragma once
#include<iostream>
#include<assert.h>
#include<math.h>
using namespace std;
struct AVLTreeNode
{
	AVLTreeNode* right;
	AVLTreeNode* left;
	AVLTreeNode* parent;
	pair<int, int> _kv;
	int _bf;
	AVLTreeNode(pair<int, int> kv)
		:right(nullptr)
		,left(nullptr)
		,parent(nullptr)
		,_kv(kv)
		,_bf(0)
	{}
};
class AVLTree
{
	typedef AVLTreeNode Node;
public:
	AVLTree()
	{
		_root = nullptr;
	}
	void InOrder()
	{
		_InOrder(_root);
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->right);
	}
	int Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int leftHeight = Height(root->left);
		int rightHeight = Height(root->right);
		return rightHeight > leftHeight ? rightHeight + 1 : leftHeight + 1;
	}
	bool IsBalance()
	{
		return _IsBalance(_root);
	}
	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}
		int leftHeight = Height(root->left);
		int rightHeight = Height(root->right);
		if ((rightHeight - leftHeight) != root->_bf)
		{
			cout << "现在是:" << root->_bf << endl;
			cout << "应该是:" << rightHeight - leftHeight << endl;
			return false;
		}
		return abs(rightHeight - leftHeight) < 2 && _IsBalance(root->left) && _IsBalance(root->right);
	}
	//右单旋
	void RotateR(Node* parent)
	{
		Node* cur = parent->left;
		Node* curL = cur->left;
		Node* curR = cur->right;
		Node* parentParent = parent->parent;
		parent->left = curR;
		if (curR)
			curR->parent = parent;
		cur->right = parent;
		parent->parent = cur;
		if (parent == _root)
		{
		    _root = cur;
			_root->parent = nullptr;
		}
		else
		{
			if (parentParent->left == parent)
			{
				parentParent->left = cur;
				cur->parent = parentParent;
			}
			else if (parentParent->right == parent)
			{
				parentParent->right = cur;
				cur->parent = parentParent;
			}
			else
			{
				assert(false);
			}
		}
		cur->_bf = 0;
		parent->_bf = 0;
	}
	//左单旋
	void RotateL(Node* parent)
	{
		Node* cur = parent->right;
		Node* curL = cur->left;
		Node* parentParent = parent->parent;
		parent->right = curL;
		if (curL)
			curL->parent = parent;
		cur->left = parent;
		parent->parent = cur;
		if (parent == _root)
		{
			_root = cur;
			_root->parent = nullptr;
		}
		else
		{
			if (parentParent->left == parent)
			{
				parentParent->left = cur;
				cur->parent = parentParent;
			}
			else if (parentParent->right == parent)
			{
				parentParent->right = cur;
				cur->parent = parentParent;
			}
			else
			{
				assert(false);
			}
		}
		parent->_bf = 0;
		cur->_bf = 0;
	}
	//左右双旋
	void RotateLR(Node* parent)
	{
		Node* subL = parent->left;
		Node* subLR =subL->right;
		int bf = subLR->_bf;
		RotateL(parent->left);
		RotateR(parent);
		if (bf == 0)
		{
			parent->_bf = 0;
			subLR->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = 0;
			subL->_bf = -1;
			subLR->_bf = 0;
		}
	}
	//右左双旋
	void RotateRL(Node* parent)
	{
		Node* subR = parent->right;
		Node* subRL = subR->left;
		int bf = subRL->_bf;
		RotateR(parent->right);
		RotateL(parent);
		if (bf == 0)
		{
			parent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = -1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}
	bool InsertNode(pair<int, int> kv)
	{
		//初始化头结点
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		//找到要插入节点的位置
		Node* cur = _root;
		Node* parent = nullptr;
		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
			{
				assert(false);
			}
		}
		//插入节点
		cur = new Node(kv);
		if (parent->_kv.first<kv.first)
		{
			parent->right = cur;
			cur->parent = parent;
		}
		else if (parent->_kv.first>kv.first)
		{
			parent->left = cur;
			cur->parent = parent;
		}
		else
		{
			assert(false);
		}
		//更新插入节点以上的平衡因子
		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)
			{
				if (parent->_bf == -2 && cur->_bf == -1)
				{
					RotateR(parent);//右单旋
				}
				else if (parent->_bf == 2 && cur->_bf == 1)
				{
					RotateL(parent);//左单旋
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
					RotateRL(parent);
				}
			}
			else
			{
				assert(false);
			}
		}
	}
private:
	Node* _root;
};

测试代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"AVLTree.h"
void TestRotateR()
{
	AVLTree t;
	t.InsertNode(make_pair(5, 1));
	t.InsertNode(make_pair(4, 1));
	t.InsertNode(make_pair(3, 1));
	t.InsertNode(make_pair(2, 1));
	t.InsertNode(make_pair(1, 1));
	t.InsertNode(make_pair(0, 1));
	t.InOrder();
	cout << t.IsBalance() << endl;
}
void TestRotateL()
{
	AVLTree t;
	t.InsertNode(make_pair(0, 1));
	t.InsertNode(make_pair(1, 1));
	t.InsertNode(make_pair(2, 1));
	t.InsertNode(make_pair(3, 1));
	t.InsertNode(make_pair(4, 1));
	t.InsertNode(make_pair(5, 1));
	t.InOrder();
	cout << t.IsBalance() << endl;
}
void Testbf()
{
	AVLTree t;
	t.InsertNode(make_pair(5, 1));
	t.InsertNode(make_pair(7, 1));
	t.InsertNode(make_pair(3, 1));
	t.InsertNode(make_pair(4, 1));
	t.InsertNode(make_pair(2, 1));
	t.InsertNode(make_pair(8, 1));
	t.InsertNode(make_pair(9, 1));
	t.InsertNode(make_pair(6, 1));
	t.InsertNode(make_pair(1, 1));
	t.InsertNode(make_pair(11, 1));
	t.InOrder();
	cout << t.IsBalance() << endl;
}
void TestRL()
{
	AVLTree t;
	t.InsertNode(make_pair(60, 1));
	t.InsertNode(make_pair(50, 1));
	t.InsertNode(make_pair(90, 1));
	t.InsertNode(make_pair(100, 1));
	t.InsertNode(make_pair(80, 1));
	t.InsertNode(make_pair(70, 1));
	t.InOrder();
	cout << t.IsBalance() << endl;
}
void TestLR()
{
	AVLTree t;
	t.InsertNode(make_pair(90, 1));
	t.InsertNode(make_pair(100, 1));
	t.InsertNode(make_pair(60, 1));
	t.InsertNode(make_pair(50, 1));
	t.InsertNode(make_pair(70, 1));
	t.InsertNode(make_pair(80, 1));
	t.InOrder();
	cout << t.IsBalance() << endl;
}
int main()
{
	//TestRotateR();
	//Testbf();
	//TestRotateL();
	//TestRL();
	TestLR();
}

以上就是C++数据结构之AVL树的实现的详细内容,更多关于C++ AVL树的资料请关注我们其它相关文章!

(0)

相关推荐

  • C语言数据结构之平衡二叉树(AVL树)实现方法示例

    本文实例讲述了C语言数据结构之平衡二叉树(AVL树)实现方法.分享给大家供大家参考,具体如下: AVL树是每个结点的左子树和右子树的高度最多差1的二叉查找树. 要维持这个树,必须在插入和删除的时候都检测是否出现破坏树结构的情况.然后立刻进行调整. 看了好久,网上各种各种的AVL树,千奇百怪. 关键是要理解插入的时候旋转的概念. // // AvlTree.h // HelloWorld // Created by feiyin001 on 17/1/9. // Copyright (c) 201

  • Springboot整合Netty实现RPC服务器详解流程

    目录 一.什么是RPC? 二.实现RPC需要解决那些问题? 1. 约定通信协议格式 RPC请求 RPC响应 2. 序列化方式 3. TCP粘包.拆包 4. 网络通信框架的选择 三.RPC服务端 四.RPC客户端 总结 一.什么是RPC? RPC(Remote Procedure Call)远程过程调用,是一种进程间的通信方式,其可以做到像调用本地方法那样调用位于远程的计算机的服务.其实现的原理过程如下: 本地的进程通过接口进行本地方法调用. RPC客户端将调用的接口名.接口方法.方法参数等信息利

  • C++实现AVL树的完整代码

    AVL树的介绍 AVL树是一种自平衡的二叉搜索树,它通过单旋转(single rotate)和双旋转(double rotate)的方式实现了根节点的左子树与右子树的高度差不超过1,.这有效的降低了二叉搜索树的时间复杂度,为O(log n).那么,下面小编将详细介绍C++实现AVL树的代码.最后一步提供可靠的代码实现 这里先粘贴代码 给大家的忠告,一定要及时去实现,不然之后再实现要花更多的时间 /* *平衡二叉树应该有些功能 *插入 删除 查找 *前序遍历 中序遍历 后序遍历 层次遍历 *统计结

  • 详解如何用c++实现平衡二叉树

    一.概述 平衡二叉树具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN).但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多. 平衡二叉树大部分操作和二叉查找树类似,主要不同在于插入删除的时候平衡二叉树的平衡可能被改变,并且只有从那些插入点到根结点的路径上的结点的平衡性可能被改

  • C++实现AVL树的基本操作指南

    目录 AVL树的概念 AVL树的插入 AVL树的四种旋转 右单旋 左单旋 左右双旋 右左双旋 查找 其他接口 析构函数 拷贝构造 拷贝赋值 总结 AVL树的概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下.因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需

  • C++数据结构之AVL树的实现

    目录 1.概念 (1)二叉搜索树的缺点 (2)定义节点 2.插入 (1)拆分 (2)找节点与插节点 (3)更新平衡因子与旋转 3.判断 4.完整代码及测试代码 完整代码 测试代码 1.概念 (1)二叉搜索树的缺点 要手撕AVL树,我们首先要知道什么是AVL树.AVL树是在二叉搜索树的基础之上改造的.当我们插入的是一个有序的序列的时候,二叉搜素树会使用一条直线来进行存储,这样并不利于查找. 当遇到这种情况的时候我们就需要对这棵树来进行调整.AVL树会通过旋转等操作,来规避这种情况.最终满足每一个节

  • 数据结构之AVL树详解

    1. 概述 AVL树是最早提出的自平衡二叉树,在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis.AVL树种查找.插入和删除在平均和最坏情况下都是O(log n),增加和删除可能需要通过一次或多次树旋转来重新平衡这个树.本文介绍了AVL树的设计思想和基本操作. 2. 基本术语 有四种种情况可能导致二叉查找树不平衡,分别为: (1)LL:插入一个新节点到根节点的左子树(Left)的左子树

  • 图解AVL树数据结构输入与输出及实现示例

    目录 AVL树(平衡二叉树): AVL树的作用: AVL树的基本操作: AVL树的插入,单旋转的第一种情况---右旋: AVL树的插入,单旋转的第二种情况---左旋: AVL树的插入,双旋转的第一种情况---左右(先左后右)旋: AVL树的插入,双旋转的第二种情况---右左(先右后左)旋: AVL树的插入代码实现:(仅供参考) AVL树(平衡二叉树): AVL树本质上是一颗二叉查找树,但是它又具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树

  • C++数据结构AVL树全面分析

    目录 概念 AVL树的实现

  • 数据结构之伸展树详解

    1. 概述 二叉查找树(Binary Search Tree,也叫二叉排序树,即Binary Sort Tree)能够支持多种动态集合操作,它可以用来表示有序集合.建立索引等,因而在实际应用中,二叉排序树是一种非常重要的数据结构. 从算法复杂度角度考虑,我们知道,作用于二叉查找树上的基本操作(如查找,插入等)的时间复杂度与树的高度成正比.对一个含n个节点的完全二叉树,这些操作的最坏情况运行时间为O(log n).但如果因为频繁的删除和插入操作,导致树退化成一个n个节点的线性链(此时即为一个单链表

  • MySQL底层数据结构选用B+树的原因

           我们都知道MySQL底层数据结构是选用的B+树,那为什么不用红黑树,或者其他什么数据结构呢?         红黑树是一种自平衡二叉查找树,Java8中的hashmap就用到红黑树来优化它的查询效率,可见,红黑树的查询效率还是比较高的,但是为什么MySQL的底层不用红黑树而用B+数呢?         下图是红黑树依次插入1,2,3,4,5,6之后的情况:  然后再在上面的红黑树中插入7:        可以看到,尽管红黑树经过了自平衡,数据整体仍然偏向树的右侧,如果继续添加更多数

  • C++AVL树4种旋转详讲(左单旋、右单旋、左右双旋、右左双旋)

    目录 引子:AVL树是因为什么出现的? 1.AVl树的的特性 2.AVl树的框架 3.AVL树的插入 3.1四种旋转(左单旋.右单旋.左右双旋.右左双旋) 3.1.1左单旋 3.1.2右单旋 3.1.3左右双旋 3.1.4右左双旋 附:AVL的性能 总结 引子:AVL树是因为什么出现的? 二叉搜索树可以缩短查找的效率,如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下时间复杂度:O(N) 两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.L

  • C语言数据结构之中缀树转后缀树的实例

    C语言数据结构之中缀树转后缀树的实例 对于一个中缀表达式 a+b*c*(d-e/f) 转换成后缀是这样的形式 abc*def/-+ 后缀表达式是相当有用处的,转换成后缀表达式后求值会简单很多.那么该如何转换呢? 网上关于这方面的资料一搜一大把,每本数据结构的书中都会提及这个算法,在这个算法中,用到 栈 这个数据结构. 1,关键是比较运算符的优先级,谁的优先级高,谁就出现在前面上面的表达式中,有括号的时候括号优先级最高,*/次之,+-最后. 在上面的表达式中+的优先级不如*的高,因此,在后缀表达式

  • Java数据结构学习之树

    一.树 1.1 概念 与线性表表示的一一对应的线性关系不同,树表示的是数据元素之间更为复杂的非线性关系. 直观来看,树是以分支关系定义的层次结构. 树在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可以用树的形象来表示. 简单来说,树表示的是1对多的关系. 定义(逻辑结构): 树(Tree)是n( n>=0 )个结点的有限集合,没有结点的树称为空树,在任意一颗非空树中: 有且仅有一个特定的称为根(root)的结点 . 当n>1的时,其余结点可分为 m( m>0 ) 个互不相交的

随机推荐