数据结构之平衡二叉树

平衡二叉树是精华版的二叉排序树,但是将一个完整的二叉排序树直接转换为平衡二叉树代价并不小,因为你是将一个已经构造完成的二叉排序树转换为平衡二叉树,这里需要区分的,很多博客讲平衡二叉树时候都说是将二叉排序树转换为平衡二叉树,其实不然。

因为那只是我们构造平衡二叉树的过程,而不能说成是二叉排序树转换为平衡二叉树,因为平衡二叉树拥有二叉平衡树的性质,打个最简单的比方:我们将一颗二叉树建立成为二叉排序树,难道你会说,我们是将二叉树转换为二叉排序树,很显然不会,我们一般直接说的是构造一个二叉排序树。

所以将二叉排序树转换为平衡二叉树,和构造平衡二叉树是不同的,还有就是之前说的,将构造完成的二叉排序树转换为平衡二叉树我们需要使用构造平衡二叉树的方法,也就是说实际上我们将一颗二叉排序树转换为平衡二叉树的过程可以说不是转换,因为我们需要一步一步的从二叉排序树中取一个节点然后加入到平衡二叉树中,而不是直接对二叉排序树进行左旋右旋操作,如果你直接对二叉排序树进行左旋右旋操作来构造一个平衡二叉树的话,你会发现很麻烦。

这里稍微提一下,平衡二叉树是干什么的,平衡二叉树只是让二叉排序树的深度最少,换句话来说平衡二叉树是一个深度最小的二叉排序树。

然后呢,平衡二叉树主要有两个操作一个是左旋,一个是右旋(左旋和右旋的区别就是一个是整体节点往左移,一个是整体节点往右移),针对具体的情况,会有四种情况要处理,左左,右右,左右,右左,具体是什么情况,百度直接就可以搜到,本博客主要是书写代码。

下面就是一个右旋的操作:

这里写图片描述

当我们增加节点的时候会让B的子树深度和A的子树深度相差 2 <script type="math/tex" id="MathJax-Element-1">2</script>,所以我们需要调整它们:

这里写图片描述

这里的代码我写了两个东西,一个是二叉排序树,一个是平衡二叉树,之前说过平衡二叉树也是一个二叉排序树,所以平衡二叉树继承二叉排序树,然后呢,所以不管他们怎么调整,中序遍历的结果都是一样的。

之前代码有点问题,修正完成

代码:

#include <map>
#include <queue>
#include <vector>
#include <string>
#include <cstdio>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>

#define FIN freopen("input.txt", "r", stdin)
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MAXN = 1e6 + 5;
const int MAXM = 1e2 + 5;
const LL INF = 1LL << 40;
const int mod = 1e9 + 7;

template<typename T>
class BTree;
template<typename T>
class TreeNode {
    public:
        TreeNode * lchild, *rchild;
        T data;//数据域
        int hgt;//子树高度
        TreeNode(T data) : data(data), hgt(0) {
            lchild = rchild = NULL;
        }
        bool operator < (TreeNode & a) const {
            return data < a.data;
        }
};
template<typename T>
class PTree {
    protected:

        typedef pair<TreeNode<T> *, int> PTI;
        void insertNode(TreeNode<T>*& root, T nd);//插入节点
        void deleteNode(TreeNode<T>*& root);//删除节点
        void pri_midprint(TreeNode<T>*& root);//中序打印
    public:
        TreeNode<T> * root;//根节点
        friend class BTree<T>;
        PTree() {
            root = NULL;
        }
        ~PTree() {
            deleteNode(root);
        }
        void insert(T nd);
        int height(TreeNode<T> * root);
        void print();//形象的打印二叉树
        void midprint();
};

template<typename T>
int PTree<T>::height(TreeNode<T> * root) {
    if(!root) return 0;
    return root -> hgt = max(height(root -> lchild), height(root -> rchild)) + 1;
}

template<typename T>
void PTree<T>::insert(T nd) {
    this -> insertNode(root, nd);
}

template<typename T>
void PTree<T>::deleteNode(TreeNode<T>*& root) {
    if(!root || !root -> lchild && !root -> rchild) {
        delete root;
        return;
    }
    deleteNode(root -> lchild);
    deleteNode(root -> rchild);
    delete root;
}

template<typename T>
void PTree<T>::insertNode(TreeNode<T>*& root, T nd) {
    if(!root) {
        root = new TreeNode<T>(nd);
        this -> height(root);
        return;
    }
    if(root -> data >= nd) {
        if(!root -> lchild) root -> lchild = new TreeNode<T>(nd);
        else insertNode(root -> lchild, nd);
    } else {
        if(!root -> rchild) root -> rchild = new TreeNode<T>(nd);
        else insertNode(root -> rchild, nd);
    }
}

template<typename T>
void PTree<T>::pri_midprint(TreeNode<T>*& root) {
    if(!root) return;
    pri_midprint(root -> lchild);
    cout << "[" << root -> data << "]";
    pri_midprint(root -> rchild);
}

template<typename T>
void PTree<T>::midprint() {
    pri_midprint(root);
    cout << endl;
}

template<typename T>
void PTree<T>::print() {
    int zwidth = (1 << height(root)) * 4;
    queue<PTI> q;
    q.push(PTI(root, 0));
    int maxv = -1, zmaxv = -1;
    bool flag = false;
    while(!q.empty()) {
        PTI nd = q.front();
        q.pop();
        if(maxv < nd.second) {
            cout << endl;
            flag = true;
            zwidth /= 2;
        } else flag = false;
        if(nd.second - 2 >= zmaxv) break;
        maxv = nd.second;
        cout.width(flag ? zwidth / 2 : zwidth);
        if(nd.first) {
            zmaxv = nd.second;
            cout << nd.first -> data;
        } else {
            cout << '-';
        }
        q.push(PTI(nd.first ? nd.first -> lchild : NULL, nd.second + 1));
        q.push(PTI(nd.first ? nd.first -> rchild : NULL, nd.second + 1));
    }
}


template<typename T>
class BTree : public PTree<T> {
    private:
        void insertNode(TreeNode<T>*& root, T nd);
        void Lact(TreeNode<T>*& nd);//左旋,这里要看清楚,用的是指针变量引用。
        void Ract(TreeNode<T>*& nd);//右旋
        void LLact(TreeNode<T>*& nd);//左左情况
        void RRact(TreeNode<T>*& nd);//右右情况
        void LRact(TreeNode<T>*& nd);//左右情况
        void RLact(TreeNode<T>*& nd);//右左情况
        void PtoBTreeact(TreeNode<T>*& root);
    public:
        void PtoBTree(PTree<int> &p);//将二叉排序树转换为平衡二叉树
        void insert(T nd);
        BTree() {};
};

template<typename T>
void BTree<T>::PtoBTreeact(TreeNode<T>*& root){
    if(!root) return;
    this -> PtoBTreeact(root -> lchild);
    this -> insert(root -> data);
    this -> PtoBTreeact(root -> rchild);
 }
template<typename T>
void BTree<T>::PtoBTree(PTree<int> &p){
    this -> PtoBTreeact(p.root);
 }
template<typename T>
void BTree<T>::Lact(TreeNode<T>*& nd) {
    TreeNode<T>* nnd = nd;
    TreeNode<T>* ndR = nd -> rchild;
    TreeNode<T>* ndRL = ndR -> lchild;
    nd -> rchild = ndRL;
    nd = ndR;
    ndR -> lchild = nnd;
}
template<typename T>
void BTree<T>::Ract(TreeNode<T>*& nd) {
    TreeNode<T>* nnd = nd;
    TreeNode<T>* ndL = nd -> lchild;
    TreeNode<T>* ndLR = ndL -> rchild;
    nd -> lchild = ndLR;
    nd = ndL;
    ndL -> rchild = nnd;
}
template<typename T>
void BTree<T>::LLact(TreeNode<T>*& nd) {
    Lact(nd);
}
template<typename T>
void BTree<T>::RRact(TreeNode<T>*& nd) {
    Ract(nd);
}
template<typename T>
void BTree<T>::LRact(TreeNode<T>*& nd) {
    Lact(nd -> lchild);
    Ract(nd);
}
template<typename T>
void BTree<T>::RLact(TreeNode<T>*& nd) {
    Ract(nd -> rchild);
    Lact(nd);
}

template<typename T>
void BTree<T>::insert(T nd) {
    this -> insertNode(this -> root, nd);
}

template<typename T>
void BTree<T>::insertNode(TreeNode<T>*& root, T nd) {
    if(!root) {
        root = new TreeNode<T>(nd);
        this -> height(root);
        return;
    }
    if(root -> data >= nd) {
        if(!root -> lchild) root -> lchild = new TreeNode<T>(nd);
        else insertNode(root -> lchild, nd);
    } else {
        if(!root -> rchild) root -> rchild = new TreeNode<T>(nd);
        else insertNode(root -> rchild, nd);
    }

    TreeNode<T> *ndL = root -> lchild;
    TreeNode<T> *ndR = root -> rchild;
    /*这里是四种情况的区分,左旋右旋是基本操作,而真实操作时,并不是直接左旋右旋,而是通过左旋右旋完成一种功能*/
    if(ndL && this -> height(ndL) - this -> height(ndR) > 1 && this -> height(ndL -> lchild) - this -> height(ndL -> rchild) > 0) {
        RRact(root);
    } else if(ndR && this -> height(ndR) - this -> height(ndL) > 1 && this -> height(ndR -> rchild) - this -> height(ndR -> lchild) > 0) {
        LLact(root);
    } else if(ndL && this -> height(ndL) - this -> height(ndR) > 1 && this -> height(ndL -> rchild) - this -> height(ndL -> lchild) > 0) {
        LRact(root);
    } else if(ndR && this -> height(ndR) - this -> height(ndL) > 1 && this -> height(ndR -> lchild) - this -> height(ndR -> rchild) > 0) {
        RLact(root);
    }
}
void test1() {
    PTree<int> p;
    p.insert(6);
    p.insert(2);
    p.insert(7);
    p.insert(1);
    p.insert(4);
    p.insert(3);
    p.print();
    p.midprint();
    BTree<int> pp;
    pp.PtoBTree(p);

    pp.print();
    pp.midprint();
}


int main() {
    test1();
    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值