課本上講的是用指針建立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;
}