平衡二叉树

本文介绍了一个二叉树类的实现,包括添加、删除和查找数据等基本操作,并通过层序遍历验证了操作的有效性。文章提供了完整的源代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://zhuanlan.zhihu.com/p/27700617
1.tree.hpp

 #include <vector>
using std::vector;

//元素节点
typedef struct _TREE_NODE
{
    int nElement;            //数据
    _TREE_NODE* pLChild;     //左子树
    _TREE_NODE* pRChild;     //右子树
}TREE_NODE, *PTREE_NODE;

class CTree
{
public:
    CTree();
    ~CTree();
public:
    bool AddData(int nData);   //添加元素
    bool DelData(int nData);   //删除元素
    void ClearTree();          //清空元素
    void TravsoualPre();       //前序遍历
    void TravsoualMid();       //中序遍历
    void TravsoualBack();      //后序遍历
    void LevelTravsoual();     //层序遍历
    int GetCount();            //获取元素个数
    bool empty();
    bool bool cha(int nData){
        return cha(m_pRoot, nData);
    }

private:
 bool cha(TREE_NODE*& pTree, int nData){
        if (pTree==NULL) {
            return false;
        }
        else if (nData==pTree->nElement) {
            return true;
        }
        else if (nData < pTree->nElement){
            return cha(pTree->pLChild, nData);
        }
        else{
            return cha(pTree->pRChild, nData);
        }
    }
    bool AddData(PTREE_NODE& pTree, int nData);    //添加元素
    bool DelData(PTREE_NODE& pTree, int nData);    //删除元素
    int GetDeep(PTREE_NODE pTree);                 //获取深度
    void ClearTree(PTREE_NODE& pTree);             //清空元素
    PTREE_NODE GetMaxOfLeft(PTREE_NODE pTree);     //获取左子树中的最大值节点
    PTREE_NODE GetMinOfRight(PTREE_NODE pTree);    //获取又子树中的最小值节点
    void TravsoualPre(PTREE_NODE pTree);           //前序遍历
    void TravsoualMid(PTREE_NODE pTree);           //中序遍历
    void TravsoualBack(PTREE_NODE pTree);          //后序遍历

    //旋转操作
    void LeftWhirl(PTREE_NODE& pTree);       //左旋
    void RightWhirl(PTREE_NODE& pTree);      //右旋
    void LeftRightWhirl(PTREE_NODE& pTree);  //左右旋
    void RightLeftWhirl(PTREE_NODE& pTree);  //右左旋

private:
    PTREE_NODE m_pRoot;   //根节点
    int m_nCount;         //元素个数
};

2.tree.cpp

 #include <stdio.h>
 #include "Tree.hpp"

CTree::CTree() :m_pRoot(0), m_nCount(0)
{
}

CTree::~CTree()
{
}

//************************************
// Method:    AddData 添加数据
// FullName:  CTree::AddData
// Access:    private 
// Returns:   bool
// Parameter: int nData
//************************************
bool CTree::AddData(int nData)
{
    return AddData(m_pRoot, nData);
}

//************************************
// Method:    AddData
// FullName:  CTree::AddData
// Access:    private 
// Returns:   bool
// Parameter: PTREE_NODE & pTree 根节点
// Parameter: int nData
//************************************
bool CTree::AddData(TREE_NODE*& pTree, int nData)
{
    //pTree是否为空,如果为空说明有空位可以添加
    if (!pTree)
    {
        pTree = new TREE_NODE{};
        pTree->nElement = nData;
        m_nCount++;
        return true;
    }
    //与根做对比,小的放在其左子树,否则放在右子树
    if (nData > pTree->nElement)
    {
        AddData(pTree->pRChild, nData);
        //判断是否平衡
        if (GetDeep(pTree->pRChild) - 
            GetDeep(pTree->pLChild) == 2)
        {
            //判断如何旋转
            if (pTree->pRChild->pRChild)
            {
                //左旋
                LeftWhirl(pTree);
            }
            else if (pTree->pRChild->pLChild)
            {
                //右左旋
                RightLeftWhirl(pTree);
            }
        }
    }
    if (nData < pTree->nElement)
    {
        AddData(pTree->pLChild, nData);
        //判断是否平衡
        if (GetDeep(pTree->pLChild) -
            GetDeep(pTree->pRChild) == 2)
        {
            //判断如何旋转
            if (pTree->pLChild->pLChild)
            {
                //右旋
                RightWhirl(pTree);
            }
            else if (pTree->pLChild->pLChild)
            {
                //左右旋
                LeftRightWhirl(pTree);
            }
        }
    }
}

//************************************
// Method:    DelData   删除元素
// FullName:  CTree::DelData
// Access:    private 
// Returns:   bool
// Parameter: int nData
//************************************
bool CTree::DelData(int nData)
{
    return DelData(m_pRoot, nData);
}

//************************************
// Method:    DelData
// FullName:  CTree::DelData
// Access:    private 
// Returns:   bool
// Parameter: PTREE_NODE & pTree 根节点
// Parameter: int nData
//************************************
bool CTree::DelData(PTREE_NODE& pTree, int nData)
{
if (!cha(nData)) {
            cout<<"没有还删什么删!!!!!!"<<endl;
            return false;
        }
    bool bRet = false;
    //判断是否为空树
    if (empty())
    {
        return false;
    }
    //开始遍历要删除的数据
    if (pTree->nElement == nData)
    {
        //判断是否为叶子节点,是就可以直接删除,
        //不是则需要找代替
        if (!pTree->pLChild && !pTree->pRChild)
        {
            delete pTree;
            pTree = nullptr;
            m_nCount--;
            return true;
        }
        //根据左右子树的深度查找要替换的节点
        if (GetDeep(pTree->pLChild) >= 
            GetDeep(pTree->pRChild))
        {
            PTREE_NODE pMax = GetMaxOfLeft(pTree->pLChild);
            pTree->nElement = pMax->nElement;
            DelData(pTree->pLChild, pMax->nElement);
        }
        else
        {
            PTREE_NODE pMin = GetMinOfRight(pTree->pRChild);
            pTree->nElement = pMin->nElement;
            DelData(pTree->pRChild, pMin->nElement);
        }
    }
    else if (nData > pTree->nElement)
    {
        bRet = DelData(pTree->pRChild, nData);
        //判断是否平衡
        if (GetDeep(pTree->pLChild) -
            GetDeep(pTree->pRChild) == 2)
        {
            //判断如何旋转
            if (pTree->pLChild->pLChild)
            {
                //右旋
                RightWhirl(pTree);
            }
            else if (pTree->pLChild->pLChild)
            {
                //左右旋
                LeftRightWhirl(pTree);
            }
        }
    }
    else /*if (nData < pTree->nElement)*/
    {
        bRet = DelData(pTree->pLChild, nData);
        //判断是否平衡
        if (GetDeep(pTree->pRChild) -
            GetDeep(pTree->pLChild) == 2)
        {
            //判断如何旋转
            if (pTree->pRChild->pRChild)
            {
                //左旋
                LeftWhirl(pTree);
            }
            else if (pTree->pRChild->pLChild)
            {
                //右左旋
                RightLeftWhirl(pTree);
            }
        }
    }
    return bRet;
}

//************************************
// Method:    ClearTree 清空元素
// FullName:  CTree::ClearTree
// Access:    private 
// Returns:   void
//************************************
void CTree::ClearTree()
{
    ClearTree(m_pRoot);
    m_nCount = 0;
}

//************************************
// Method:    ClearTree
// FullName:  CTree::ClearTree
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE & pTree 根节点
//************************************
void CTree::ClearTree(PTREE_NODE& pTree)
{
    //从叶子节点开始删除
    //删除其左右子树后再删除根节点本身

    //判断是否为空树
    if (empty())
    {
        return;
    }
    //判断是否为叶子节点
    if (!pTree->pLChild && !pTree->pRChild)
    {
        delete pTree;
        pTree = nullptr;
        return;
    }
    ClearTree(pTree->pLChild);
    ClearTree(pTree->pRChild);
    ClearTree(pTree);
}

//************************************
// Method:    TravsoualPre 前序遍历
// FullName:  CTree::TravsoualPre
// Access:    private 
// Returns:   void
//************************************
void CTree::TravsoualPre()
{
    TravsoualPre(m_pRoot);
}

//************************************
// Method:    TravsoualPre
// FullName:  CTree::TravsoualPre
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE pTree 根节点
//************************************
void CTree::TravsoualPre(PTREE_NODE pTree)
{
    //递归的返回条件
    if (!pTree)
    {
        return;
    }
    //根左右
    printf("%d ", pTree->nElement);
    TravsoualPre(pTree->pLChild);
    TravsoualPre(pTree->pRChild);
}

//************************************
// Method:    TravsoualMid  中序遍历
// FullName:  CTree::TravsoualMid
// Access:    private 
// Returns:   void
//************************************
void CTree::TravsoualMid()
{
    TravsoualMid(m_pRoot);
}

//************************************
// Method:    TravsoualMid
// FullName:  CTree::TravsoualMid
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE pTree 根节点
//************************************
void CTree::TravsoualMid(PTREE_NODE pTree)
{
    //递归的返回条件
    if (!pTree)
    {
        return;
    }
    //左根右
    TravsoualMid(pTree->pLChild);
    printf("%d ", pTree->nElement);
    TravsoualMid(pTree->pRChild);
}

//************************************
// Method:    TravsoualBack  后序遍历
// FullName:  CTree::TravsoualBack
// Access:    private 
// Returns:   void
//************************************
void CTree::TravsoualBack()
{
    TravsoualBack(m_pRoot);
}

//************************************
// Method:    TravsoualBack
// FullName:  CTree::TravsoualBack
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE pTree 根节点
//************************************
void CTree::TravsoualBack(PTREE_NODE pTree)
{
    //递归的返回条件
    if (!pTree)
    {
        return;
    }
    //左右根
    TravsoualBack(pTree->pLChild);
    TravsoualBack(pTree->pRChild);
    printf("%d ", pTree->nElement);
}

//************************************
// Method:    层序遍历
// FullName:  CTree::LevelTravsoual
// Access:    public 
// Returns:   void
//************************************
void CTree::LevelTravsoual()
{
    vector<PTREE_NODE> vecRoot;  //保存根节点
    vector<PTREE_NODE> vecChild; //保存根节点的子节点

    vecRoot.push_back(m_pRoot);

    while (vecRoot.size())
    {
        for (int i = 0; i < vecRoot.size();i++)
        {
            printf("%d ", vecRoot[i]->nElement);
            //判断其是否左右子节点
            if (vecRoot[i]->pLChild)
            {
                vecChild.push_back(vecRoot[i]->pLChild);
            }
            if (vecRoot[i]->pRChild)
            {
                vecChild.push_back(vecRoot[i]->pRChild);
            }
        }
        vecRoot.clear();
        vecRoot = vecChild;
        vecChild.clear();
        printf("\n");
    }
}

//************************************
// Method:    GetCount  获取元素个数
// FullName:  CTree::GetCount
// Access:    public 
// Returns:   int
//************************************
int CTree::GetCount()
{
    return m_nCount;
}

//************************************
// Method:    GetDeep 获取节点深度
// FullName:  CTree::GetDeep
// Access:    private 
// Returns:   int
// Parameter: PTREE_NODE & pTree 
//************************************
int CTree::GetDeep(PTREE_NODE pTree)
{
    //判断pTree是否为空
    if (!pTree)
    {
        return 0;
    }
    int nL = GetDeep(pTree->pLChild);
    int nR = GetDeep(pTree->pRChild);
    //比较左右子树的深度,取最大值加 1 返回
    return (nL >= nR ? nL : nR) + 1;
}

//************************************
// Method:    GetMaxOfLeft 获取左子树中的最大值
// FullName:  CTree::GetMaxOfLeft
// Access:    private 
// Returns:   PTREE_NODE
// Parameter: PTREE_NODE pTree
//************************************
PTREE_NODE CTree::GetMaxOfLeft(PTREE_NODE pTree)
{
    //只要存在右子树就有更大的值
    //是否空
    if (!pTree)
    {
        return 0;
    }
    //判断是否有右子树
    while (pTree->pRChild)
    {
        pTree = pTree->pRChild;
    }
    //返回最大值节点
    return pTree;
}

//************************************
// Method:    GetMinOfRight 获取右子树中的最小值
// FullName:  CTree::GetMinOfRight
// Access:    private 
// Returns:   PTREE_NODE
// Parameter: PTREE_NODE pTree
//************************************
PTREE_NODE CTree::GetMinOfRight(PTREE_NODE pTree)
{
    //只要存在左子树就有更小的值
    //是否空
    if (!pTree)
    {
        return 0;
    }
    //判断是否有右子树
    while (pTree->pLChild)
    {
        pTree = pTree->pLChild;
    }
    return pTree;
}

//************************************
// Method:    LeftWhirl 左旋
// FullName:  CTree::LeftWhirl
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE & pTree
//************************************
void CTree::LeftWhirl(PTREE_NODE& pK2)
{
/*
   k2                  k1
     k1   ==>       k2    N
    X  N              X
*/
    //保存k1
    PTREE_NODE pK1 = pK2->pRChild;
    //保存X
    pK2->pRChild = pK1->pLChild;
    //k2变成k1的左子树
    pK1->pLChild = pK2;
    //k1变成k2
    pK2 = pK1;
}

//************************************
// Method:    RightWhirl  右旋
// FullName:  CTree::RightWhirl
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE & pTree
//************************************
void CTree::RightWhirl(PTREE_NODE& pK2)
{
/*
     k2            k1
   k1     ==>    N    k2
  N  X               X
*/
    //保存k1
    PTREE_NODE pK1 = pK2->pLChild;
    //保存X
    pK2->pLChild = pK1->pRChild;
    //k1的右子树为k2
    pK1->pRChild = pK2;
    //k2为k1
    pK2 = pK1;
}

//************************************
// Method:    LeftRightWhirl 左右旋
// FullName:  CTree::LeftRightWhirl
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE & pTree
//************************************
void CTree::LeftRightWhirl(PTREE_NODE& pK2)
{
/*
      k2               k2              N
    k1     左旋       N       右旋  K1   K2
      N             k1 [x]             [x]
       [x]     
*/
    LeftWhirl(pK2->pLChild);
    RightWhirl(pK2);
}

//************************************
// Method:    RightLeftWhirl 右左旋
// FullName:  CTree::RightLeftWhirl
// Access:    private 
// Returns:   void
// Parameter: PTREE_NODE & pTree
//************************************
void CTree::RightLeftWhirl(PTREE_NODE& pK2)
{
/*
    k2               k2                   N
       k1    右旋       N     左旋    k2     K1
     N               [x]  k1           [x]
  [x]
*/
    RightWhirl(pK2->pRChild);
    LeftWhirl(pK2);
}

bool CTree::empty()
{
    return m_pRoot == 0;
}

3.main.cpp

 #include <stdio.h>
 #include "Tree.h"

int _tmain(int argc, _TCHAR* argv[])
{
    CTree tree;

    tree.AddData(1);
    tree.AddData(2);
    tree.AddData(3);
    tree.AddData(4);
    tree.AddData(5);
    tree.AddData(6);
    tree.AddData(7);
    tree.AddData(8);
    tree.AddData(9);
    tree.AddData(10);
    tree.LevelTravsoual();
    tree.DelData(4);
    tree.LevelTravsoual();

    return 0;
}

转载于:https://blog.51cto.com/haidragon/2074624

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值