课本上讲的是用指针建立avl树,但是这种方法速度慢而且指针容易出现各种错误,实在是不是竞赛中的上上选。
现在po上顺序表建立avl树的代码。
#include<iostream>
#include<cstdio>
using namespace std;
struct node
{
//该节点的储存的值,左子树地址,右子树地址
int k, l, r, size;//size为该树的重量(包含该节点)
node()
{
k = l = r = 0;
size = 0;//未被填入数据时,空节点重量为1
}
}tree[20];
int maxnode=2, root=1;//当前可分配空间的最小节点的下标,maxnode为空,
//root为二叉树的根
void left_x(int &a)//左旋操作
{
int op = tree[a].r;
if (a == root) root = op;//若正在旋转的树为整颗子树,需要修改根节点地址
tree[a].r = tree[op].l;//该节点的右节点=右节点的左节点
tree[op].l = a;//右节点的左节点=该节点
//重点***
//为什么可以这样修改size值
//此时该子树的层次关系已经修改好,但是树的父节点与该子树的层次关系还未修改
//在子树中,op代替了原先a的位置,所以op的size是a的size
tree[op].size = tree[a].size;
//此时tree[a]节点的左右子节点已经改好,其size值就是他两个子树的size+自己的size
tree[a].size = tree[tree[a].r].size + tree[tree[a].l].size + 1;
a = op;//由于使用了引用,参数为某颗树的子树的根节点地址,修改a=op,就是修改子树根节点的地址为op
}
void right_x(int &a)
{
int op = tree[a].l;
if (a == root) root = op;
tree[a].l = tree[op].r;
tree[op].r = a;
tree[op].size = tree[a].size;
tree[a].size = tree[tree[a].r].size + tree[tree[a].l].size + 1;
a = op;
}
void balance(int &a, bool flag)//平衡子树tree[a],flag为平衡a的左子树(0)还是右子树(1)
{
if (flag)//平衡右子树,说明插入了a的右子树
{
if (tree[tree[tree[a].r].r].size > tree[tree[a].l].size)
//a的右子树的右子树的重量>a的左子树时,左旋
left_x(a);
else if (tree[tree[tree[a].r].l].size > tree[tree[a].l].size)
//a的右子树的左子树重量>a的左子树时,先对a的右子树右旋,再对a左旋
{
right_x(tree[a].r);
left_x(a);
}
else return;
}
else
{
if (tree[tree[tree[a].l].l].size > tree[tree[a].r].size)
right_x(a);
else if (tree[tree[tree[a].l].r].size > tree[tree[a].r].size)
{
left_x(tree[a].l);
right_x(a);
}
else return;
}
}
void insert(int &a,int k)//插入元素,a为插入tree中哪个元素,k为插入的值
//main函数中调用时,将root赋值给另外的变量,再用引用传递进insert
{
if ( tree[a].k==0)//tree[a]为新节点时
{
tree[a].k = k;
tree[a].size = 1;//初始化重量
tree[a].l = maxnode;//为左节点分配空间
maxnode++;
tree[a].r = maxnode;
maxnode++;//将max指针移动到未被连入avl树的空节点处
}
else
{
tree[a].size++;//要在该树的任意子树中插入,该树的重量+1
if (k < tree[a].k)
{
insert(tree[a].l, k);//插入
balance(a, 0);//调整该树
}
if (k > tree[a].k)
{
insert(tree[a].r , k);
balance(a, 1);
}
}
}
int main()
{
int b[9] = { 1,2,3,4,5,6,7,8,9 };
for (int i = 0; i < 9; i++)
{
int k = root;
//注意不能直接将root的引用传入insret,否则root的引用可能被传到其他子函数
//insert->balance->左右旋函数,在左右旋函数中最后会修改引用的值,如果直接将root的引用传入,会改变root的值
insert(k, b[i]);
}
return 0;
}