二叉搜索树(二)---AVL树

#include"BST.h"
#include"bin_tree.h"
#include<iostream>
#include<stdbool.h>
using namespace std;
#pragma once

#define Balanced(x) (stature((x).lchild) == stature((x).rchild))
#define BalFactor(x) (stature((x).lchild) - stature((x).rchild))
#define AVLBalanced(x) ((-2<BalFactor(x)) && (BalFactor(x)<2))
#define TALLER_CHILd(x) ( \
		stature( (x)->lchild ) > stature( (x)->rchild ) ? (x)->lchild : ( /*左高*/ \
	    stature( (x)->lchild ) < stature( (x)->rchild ) ? (x)->rchild : ( /*右高*/ \
	    IS_LCHILD( * (x) ) ? (x)->lchild : (x)->rchild /*等高:与父亲x同侧者(zig-zig或zag-zag)优先*/ \
		   ) \
	   ) \
	)
template<typename T>
class AVL :public BST<T>
{
public:
	bin_node_posi<T> insert(const T&);
	bool remove(const T&);
	// 旋转变换
	bin_node_posi<T> connect34(bin_node_posi<T>, bin_node_posi<T>, bin_node_posi<T>,  // 3个结点
		bin_node_posi<T>, bin_node_posi<T>, bin_node_posi<T>, bin_node_posi<T>);       // 4棵子树,返回
	bin_node_posi<T> rotate_at(bin_node_posi<T>);                                  // 返回旋转后子树的根节点

};
template<typename T> bin_node_posi<T> AVL<T>::connect34(bin_node_posi<T> a, bin_node_posi<T> b, bin_node_posi<T> c,
	bin_node_posi<T> t0, bin_node_posi<T> t1, bin_node_posi<T> t2, bin_node_posi<T> t3)
{
	a->lchild = t0; if (t0) t0->parent = a;
	a->rchild = t1; if (t1) t1->parent = a;
	this->update_height(a);                       // 插完两棵树之后再更新高度

	c->lchild = t2; if (t2) t2->parent = c;
	c->rchild = t3; if (t3) t3->parent = c;
	this->update_height(c);
	// 最后连接a,b,c
	b->lchild = a; a->parent = b;
	b->rchild = c; c->parent = b;                // 这里是双向连接
	this->update_height(b);
	return b;                                    // b 作为重构后的根节点返回
}
template<typename T> bin_node_posi<T> AVL<T>::rotate_at(bin_node_posi<T> v)
{
	bin_node_posi<T> p = v->parent;  bin_node_posi<T> g = p->parent;   // 不要用逗号连接,两句就写两句
	if(IS_RCHILD(*p))
		if (IS_RCHILD(*v))             // g,p,v 右边连成一线,zag
		{
			p->parent = g->parent;    // p是旋转后的根节点,连接父指针
			return connect34(g, p, v, g->lchild, p->lchild, v->lchild, v->rchild);
		}
		else                          // g,p 右连,v左连p,zig-zag
		{
			v->parent = g->parent;
			return connect34(g, v, p, g->lchild, v->lchild, v->rchild, p->rchild);
		}
	else                            // P是左孩子
		if (IS_LCHILD(*v))          // g,p,v 左边连成一线,zig
		{
			p->parent = g->parent;    
			return connect34(v, p, g, v->lchild, v->rchild, p->rchild, g->rchild);
		}
		else                          // g,p 左连,v右连p,zag-zig
		{
			v->parent = g->parent;
			return connect34(p, v, g, p->lchild, v->lchild, v->rchild, g->rchild);
		}
}
template<typename T> bin_node_posi<T> AVL<T>::insert(const T& e)
{
	bin_node_posi<T>& temp = this->search(e);
	if (temp != NULL) return temp;
	temp = new bin_node<T>(e, this->phit);
	for (bin_node_posi<T> g = this->phit; g; g = g->parent)    // 向上查找,找到最低的那个失衡的祖先即可进行平衡调整
	{
		/*int bal = BalFactor(*g);
		cout << bal << endl;*/
		if (!AVLBalanced(*g)) {
			FROM_PARENT_TO(*g) = rotate_at(TALLER_CHILd(TALLER_CHILd(g)));   // 即rotate_at(v)往右边更长的分支调
			break;                              // 只需调整一次
		}
		else
			this->update_height(g);            // 如果是平衡的,在此循环内,相当于update_height_above
	}
	return temp;
}
template<typename T> bool AVL<T>::remove(const T& e)
{
	bin_node_posi<T>& temp = this->search(e);              // 还是要用引用类型,否则删不了
	if (temp == NULL) return false;
	remove_at(temp,this->phit);
	for (bin_node_posi<T> g = this->phit; g; g = g->parent)
	{
		if (!AVLBalanced(*g)) {
			// FROM_PARENT_TO(*g) = rotate_at(TALLER_CHILd(TALLER_CHILd(*g))); // 这样写就完蛋了,for loop进行不下去
			// this->update_height_above(g);
			// 邓公写的
			g = FROM_PARENT_TO(*g) = rotate_at(TALLER_CHILd(TALLER_CHILd(g)));
			this->update_height(g);            // 这里没有用update_above 是因为在for循环中,还可以接着更新
		}
	}
	return true;
}
int main()
{
	AVL<int> avl;
	Visit<int> visit;
	for (int i = 1; i < 12; ++i) {
		for (int j = i; j <= i; ++j)
		{
			avl.insert(i);
		}
		avl.inorder_tra(visit);
	}
	/*for (int i = 0; i < 200; ++i)
	{
		avl.remove(rand() % 1000 + 1);
	}
	avl.inorder_tra(visit);*/
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值