順序表實現一顆avl樹

課本上講的是用指針建立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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章