数据结构笔记(五)——平衡查找树(AVLTree)(4)

AVL树是带有平衡条件的二叉查找树,这个平衡条件必须容易保持,而且必须保持树的深度是O(logN)。

树,二叉树,二叉查找树,有这么多种树,我们一步一步给树这个结构添加限制条件,保证操作简单,复杂度不那么高。AVL树添加了平衡条件这一项,为什么呢?之前的二叉查找树存在的问题是一般情况下我们无法保证它的深度足够的小,虽然完全二叉树的深度logN确实够小了,但对一般的输入保持完全二叉树却不是简单的事情。我们希望深度尽量接近logN,但实现起来复杂度不要太高。由此提出平衡这一概念,希望在复杂度和深度之间折中。

那我们怎么确定这个平衡条件呢?又怎样保持这种具有平衡条件的树的结构呢?

简单的想法自然是左右子树具有相同的高度,空子树的高度定义为-1,那2^k-1个节点的树高度为k,满足logN的条件,但是这个条件还是很难满足的诶。那就再放宽一点点条件,不要左右子树高度相同,让他们高度差不要太大,比如不超过1. 这种平衡条件是否符合深度的要求呢?我们需要考虑节点为N个的树,其深度是否为O(logN),也就是高度为h的树的最少节点不会小于2^h.

高度为h的树,其最少节点数S(h)=S(h-1)+S(h-2)+1,S(0)=1,S(1)=2.和斐波那契数列有关系。这个关系我们可以自己画一画得出,要使得节点数最少,且满足高度差不超过1,极端的情况是一边比另一边高一层。

上式左右加1,S(h)+1=[S(h-1)+1 ]+ [S(h-2) + 1]——>f(h)=f(h-1)+f(h-2)为斐波那契数列了,可以看一下f(0)对应斐波那契数列(0,1,1,2,3,5,8,13)的哪一项,f(0)=2,f(1)=3,f(2)=5,分别对应斐波那契数列的Fibonacci(3),Fibonacci(4),Fibonacci(5),即S(h)=Fibonacci(h+3)-1。斐波那契数列大致呈指数增长,树的节点数随着高度也呈指数增长,也就是节点为n的树,其高度大致为n的对数了。

另外一个问题是,我们要保证树的高度差不超过1,正常的二叉查找树插入肯定不能满足这一条件,我们在插入一个节点后,判断高度是够满足条件,对不满足条件的进行旋转

插入一个节点不满足平衡条件的有四种情况,1和4,2和3是对称的情形。

单旋转针对2,3这两种情况,双旋转针对1,4这两种情况。

单旋转:

                   

                              4的平衡被破坏                                                                                      2的平衡被破坏

双旋转(执行两次单旋转):

 

 

节点8的平衡被破坏,先进行一次单右旋转,再进行一次单左旋转

节点6的平衡被破坏,先进行一次单右旋转,再进行一次单左旋转

代码实现:

AVLTree.h

#pragma once
#include<iostream>
using namespace std;
struct AvlNode;
typedef int ElementType;
typedef AvlNode *ptrNode;
typedef ptrNode AvlTree;
ptrNode createAvlTree(ElementType e);
ptrNode findX(AvlTree t,ElementType e);
ptrNode insertX(AvlTree t, ElementType e);
ptrNode findMin(AvlTree t);
ptrNode findMax(AvlTree t);
void disposeTree(AvlTree t);
struct AvlNode
{
	ElementType element;
	ptrNode left;
	ptrNode right;
	int height;
};
static int Height(ptrNode p)
{
	if (p==nullptr)
	{
		return -1;
	}
	else
	{
		return p->height;
	}
}
static int Max(int left, int right)
{
	return left > right ? left : right;
}
static ptrNode singleRotateWithLeft(ptrNode p)
{
	ptrNode tmp = p->left;
	p->left = tmp->right;
	tmp->right = p;
	p->height = Max(Height(p->left), Height(p->right)) + 1;
	tmp->height = Max(Height(tmp->left), Height(tmp->right)) + 1;
	return tmp;
}
static ptrNode singleRotateWithRight(ptrNode p)
{
	ptrNode tmp = p->right;
	p->right = tmp->left;
	tmp->left = p;
	p->height= Max(Height(p->left), Height(p->right)) + 1;
	tmp->height = Max(Height(tmp->left), Height(tmp->right)) + 1;
	return tmp;
}
//保证p有左儿子,p的左儿子有右儿子
static ptrNode doubleRotateWithLeft(ptrNode p)
{
	p->left = singleRotateWithRight(p->left);
	return singleRotateWithLeft(p);
}
//保证p有右儿子,p的右儿子有左儿子
static ptrNode doubleRotateWithRight(ptrNode p)
{
	p->right = singleRotateWithLeft(p->right);
	return singleRotateWithRight(p);
}
static void inorder(AvlTree t)
{
	if (t==nullptr)
	{
		return;
	}
	inorder(t->left);
	cout << t->element << " ";
	inorder(t->right);
	
}

AVLTree.cpp

// AVLTree.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "AVLTree.h"
ptrNode createAvlTree(ElementType e)
{
	ptrNode node = (ptrNode)malloc(sizeof(struct AvlNode));
	if (node==nullptr)
	{
		return nullptr;
	}
	node->element = e;
	node->height = 0;
	node->left = nullptr;
	node->right = nullptr;
	return node;
}
ptrNode findX(AvlTree t,ElementType e)
{
	if (t==nullptr)
	{
		return nullptr;
	}
	if (e>t->element)
	{
		return findX(t->right, e);
	}
	else if(e<t->element)
	{
		return findX(t->left, e);
	}
	return t;
}
ptrNode findMin(AvlTree t)
{
	if (t == nullptr)
	{
		return nullptr;
	}
	if (t->left==nullptr)
	{
		return t;
	}
	else
	{
		return findMin(t->left);
	}
}
ptrNode findMax(AvlTree t)
{
	if (t == nullptr)
	{
		return nullptr;
	}
	if (t->right == nullptr)
	{
		return t;
	}
	else
	{
		return findMax(t->right);
	}
}
ptrNode insertX(AvlTree t, ElementType e)
{
	if (t==nullptr)
	{
		t = createAvlTree(e);
	}
	else if(e>t->element)
	{
		t->right = insertX(t->right, e);
		if (Height(t->right)-Height(t->left)==2)
		{
			if (e>t->right->element)
			{
				t = singleRotateWithRight(t);
			}
			else
			{
				t = doubleRotateWithRight(t);
			}
		}
	}
	else if(e<t->element)
	{
		t->left = insertX(t->left, e);
		if (Height(t->left)-Height(t->right)==2)
		{
			if (e<t->left->element)
			{
				t=singleRotateWithLeft(t);
			}
			else
			{
				t = doubleRotateWithLeft(t);
			}
		}
	}
	t->height = Max(Height(t->left), Height(t->right)) + 1;
	return t;
}
void disposeTree(AvlTree t)
{
	if (t==nullptr)
	{
		return;
	}
	disposeTree(t->left);
	disposeTree(t->right);
	free(t);
}

test.cpp

#include "stdafx.h"
#include "AVLTree.h"
int main()
{
	AvlTree tree = createAvlTree(3);
	tree = insertX(tree, 3);
	tree = insertX(tree, 2);
	tree = insertX(tree, 1);
	tree = insertX(tree, 4);
	tree = insertX(tree, 5);
	tree = insertX(tree, 6);
	tree = insertX(tree, 7);

	tree = insertX(tree, 16);
	tree = insertX(tree, 15);
	tree = insertX(tree, 14);
	tree = insertX(tree, 13);
	tree = insertX(tree, 12);
	tree = insertX(tree, 11);
	tree = insertX(tree, 10);
	tree = insertX(tree, 9);
	tree = insertX(tree, 8);
	cout << "max: "<< findMax(tree)->element << endl;
	cout << "min: " << findMin(tree)->element << endl;
	inorder(tree);
	cout << endl;
	disposeTree(tree);
	return 0;
}

结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值