二叉树操作实现

二叉树操作实现

什么是二叉树?

树是常用的一种非线性数据结构。

树有很多衍生分类,其中,二叉树便是最为常见的一种。

二叉树的定义是以递归形式给出的:一棵二叉树是结点的一个有限集合,该集合可能为空,或则是由一个根节点加上两棵分别称为左子树、右子树的、互不相交的二叉树组成。

二叉树的特点是每个结点最多有两个子女,分别image-20211026211620558称为该节点的左子树和右子树。

在二叉树中不存在度大于2的结点,并且二叉树的字子树有左子树、右子树之分,其子树的次序不能颠倒。

二叉树是分支数最大不超过2的有根有序树。

二叉树的性质

image-20211024150453728

二叉树的基本操作?

二叉树的基本操作有:

  • 创建二叉树
  • 前序遍历
  • 中序遍历
  • 后序遍历
  • 层序遍历
  • 求结点个数
  • 求二叉树的深度
  • 销毁二叉树
  • 前/中/后序遍历的非递归实现
  • 求叶子结点个数
  • 求某结点的双亲结点
  • 删除某节点的子树

二叉树相关算法的基本模式

由于树本身的定义就是递归定义的,

所以二叉树的基本操作多半基于递归思想实现。

二叉树结点结构体的设计

//结点结构体的定义
struct BiNode
{
    /* data */
    int data;
    BiNode *lchild; //左孩子
    BiNode *rchild; //右孩子
};

二叉树类的设计

我在设计类的时候,将涉及到对于结点root进行操作的递归调用过程的权限置为了private,并在public权限下设计了对外接口,这样做的目的是避免外界直接对根节点进行操作,是一种保护行为。

本质是函数重载和递归思想的实现。

class BiTree
{
private:
    /* data */
    int IsRoot=0;
    BiNode *Creat();                //构造函数调用
    void Release(BiNode *bt);       //析构函数调用
    void PreOrder(BiNode *bt);      //前序遍历函数调用
    void InOrder(BiNode *bt);       //中序遍历函数调用
    void PostOrder(BiNode *bt);     //后序遍历函数调用过程
    int Size(BiNode *bt);           //获取结点个数调用过程
    int Leaf(BiNode *bt);           //求叶子结点个数的调用过程
    void Parent(BiNode *bt);        //求双亲结点调用过程
    int Height(BiNode *bt);         //获取二叉树高度的调用过程
    int DelX(BiNode *bt,int x,int flag);    //删除子树的递归调用过程
    BiNode *root;                   //指向根节点的头指针
    int target;
public:
    //BiNode *root;
    BiTree(){this->root=Creat();}   //构造函数  建立一棵二叉树
    ~BiTree(){Release(root);}       //析构函数,释放各结点的存储空间
    void PreOrder(){PreOrder(root);}    //前序遍历二叉树
    void InOrder(){InOrder(root);}      //中序遍历二叉树
    void PostOrder(){PostOrder(root);}  //后序遍历二叉树
    int Size(){return Size(root);}      //获取二叉树结点个数
    int Leaf(){return Leaf(root);}      //获取二叉树中叶子结点个数
    int Height(){return Height(root);}  //获取二叉树的高度(深度)
    void PreOrderN();                   //前序遍历算法非递归实现
    void InOrderN();                    //中序遍历算法非递归实现
    void Parent(int x);                 //寻找双亲结点
    void DelX(int x,int flag){DelX(root,x,flag);}   //删除值为x的结点的子树
    void LevelOrder();                  //层序遍历
};

二叉树类的各算法实现

创建二叉树

创建时需要自己指定规则

image-20211026211639901

BiNode *BiTree::Creat()
{
    //可以采用广义表的方法去建立二叉树
    // if(IsRoot==0)
    // {
    //     cout<<"请输入根结点数据域(0表示空)"
    // }
    BiNode *bt;
    int da; //临时变量
    cout << "请输入该结点数据域(0表示空):";
    cin >> da;
    if (da == 0)
    {
        bt = nullptr;
    }
    else
    {
        bt = new BiNode;
        bt->data = da;
        bt->lchild = Creat(); //递归调用创建结点方法
        bt->rchild = Creat(); //递归调用创建结点方法
    }
    return bt; //返回总树及每一棵子树的根节点root
}

销毁二叉树

销毁二叉树实际是后序遍历的一种操作

void BiTree::Release(BiNode *bt)
{
    //析构函数的调用过程
    cout << "析构" << endl;
    //和后续遍历的思想一致
    //左子树  右子树  根节点

    //递归终止条件
    if (bt == nullptr)
    {
        return;
    }
    else
    {
        Release(bt->lchild); //递归调用释放左子树
        Release(bt->rchild); //递归调用释放右子树
        delete bt;
    }
    cout << "析构成功" << endl;
}

前序遍历(递归)

前/中/后序遍历的递归算法基本一致,在此只对前序遍历进行说明。

void BiTree::PreOrder(BiNode *bt)
{
    //递归调用的终止条件
    if (bt == nullptr)
    {
        return;
    }
    else
    {
        //前序遍历: 根节点  左子树  右子树
        cout << bt->data << " "; //输出数据域
        PreOrder(bt->lchild);
        PreOrder(bt->rchild);
    }
}

求二叉树的总结点个数

递归

int BiTree::Size(BiNode *bt)
{
    if (bt == nullptr)
    {
        return 0;
    }
    return 1 + Size(bt->lchild) + Size(bt->rchild);
}

求叶子结点个数

递归

int BiTree::Leaf(BiNode *bt)
{
    //递归实现
    if (bt == nullptr)
    {
        return 0;
    }
    if (bt->lchild == nullptr && bt->rchild == nullptr)
    {
        return 1;
    }
    return Leaf(bt->lchild) + Leaf(bt->rchild); //递归调用子函数,求子树中叶子结点的个数
}

求二叉树的深度

int BiTree::Height(BiNode *bt)
{
    //求二叉树的高度(深度)
    if (bt == nullptr)
    {
        return 0;
    }
    int i = Height(bt->lchild);
    int j = Height(bt->rchild);
    return i < j ? j + 1 : i + 1;
}

前序遍历非递归实现

基于顺序栈

void BiTree::PreOrderN()
{
    //前序遍历算法的非递归实现
    BiNode *bt = this->root;
    BiNode *S[100]; //顺序栈 直接基于数组实现
    int top = -1;   //顺序栈初始化
    while (bt != nullptr || top != -1)
    {
        //终止条件:是空树且栈为空栈
        while (bt != nullptr)
        {
            cout << bt->data << " ";
            S[++top] = bt; //根指针入栈
            bt = bt->lchild;
        }
        if (top != -1)
        {
            bt = S[top--];
            bt = bt->rchild;
        }
    }
}

求某结点的双亲

void BiTree::Parent(int x)
{
    //int重载
    this->target = x; //更改靶子的值
    Parent(root);     //开始寻找双亲
}

void BiTree::Parent(BiNode *bt)
{
    if (bt != nullptr)
    {
        if (bt->lchild != nullptr && bt->lchild->data == target)
        {
            cout << "值为" << target << "的结点的双亲结点的值为" << bt->data << endl;
            return;
        }
        if (bt->rchild != nullptr && bt->rchild->data == target)
        {
            cout << "值为" << target << "的结点的双亲结点的值为" << bt->data << endl;
            return;
        }
        else
        {
            Parent(bt->lchild);
            Parent(bt->rchild);
        }
    }
}

删除以某结点为根的子树

int BiTree::DelX(BiNode *bt, int x, int flag)
{
    //删除值为x的结点的子树  递归方法实现  flag为标志 用于记录并判断
    if (bt == nullptr)
    {
        return 0;
    }
    else
    {
        if (bt->data == x) //如果当前结点的值为x,则更改标志,并将标志向下传递
        {
            flag = 1;
        }

        int leftFlag = DelX(bt->lchild, x, flag);  //递归左子树
        int rightFlag = DelX(bt->rchild, x, flag); //递归右子树

        if (1 == flag) //若flag为1,则说明其先祖结点有值为x,该子结点需要被删除
        {
            if (bt->data == x) //若其数据域为x,则应向上传递标志为1,以便赋空
            {
                return 1;
            }
            delete bt;
        }
        else
        {
            if (1 == leftFlag)
            {
                bt->lchild = nullptr; //从子结点接受收的信息,即如果其子结点为x,需要将其指针域赋空
            }

            if (1 == rightFlag)
            {
                bt->rchild == nullptr; //从子结点接受收的信息,即如果其子结点为x,需要将其指针域赋空
            }
        }
    }
    return 0;
}

层序遍历

基于队列

void BiTree::LevelOrder()
{
    //层序遍历 基于队列
    BiNode *Q[100]; //所需队列
    BiNode *q = nullptr;

    int front = -1, rear = -1; //队列初始条件
    if (root == nullptr)
    {
        //空树不操作
        return;
    }

    Q[++rear] = root; //根指针入队
    while (front != rear)
    {
        //遍历条件:当队列非空时
        q = Q[++front]; //出队
        cout << q->data << " ";
        if (q->lchild != nullptr)
            Q[++rear] = q->lchild;
        if (q->rchild != nullptr)
            Q[++rear] = q->rchild;
    }
}

源代码

BiTree.h

/*
二叉树
树结构本身是递归定义的
在这里,我们整个数据结构的定义和实现也大多基于递归
与欢行
*/

#include<iostream>
#include"queue"
using namespace std;

//结点结构体的定义
struct BiNode
{
    /* data */
    int data;
    BiNode *lchild; //左孩子
    BiNode *rchild; //右孩子
};

class BiTree
{
private:
    /* data */
    int IsRoot=0;
    BiNode *Creat();                //构造函数调用
    void Release(BiNode *bt);       //析构函数调用
    void PreOrder(BiNode *bt);      //前序遍历函数调用
    void InOrder(BiNode *bt);       //中序遍历函数调用
    void PostOrder(BiNode *bt);     //后序遍历函数调用过程
    int Size(BiNode *bt);           //获取结点个数调用过程
    int Leaf(BiNode *bt);           //求叶子结点个数的调用过程
    void Parent(BiNode *bt);        //求双亲结点调用过程
    int Height(BiNode *bt);         //获取二叉树高度的调用过程
    int DelX(BiNode *bt,int x,int flag);    //删除子树的递归调用过程
    BiNode *root;                   //指向根节点的头指针
    int target;
public:
    //BiNode *root;
    BiTree(){this->root=Creat();}   //构造函数  建立一棵二叉树
    ~BiTree(){Release(root);}       //析构函数,释放各结点的存储空间
    void PreOrder(){PreOrder(root);}    //前序遍历二叉树
    void InOrder(){InOrder(root);}      //中序遍历二叉树
    void PostOrder(){PostOrder(root);}  //后序遍历二叉树
    int Size(){return Size(root);}      //获取二叉树结点个数
    int Leaf(){return Leaf(root);}      //获取二叉树中叶子结点个数
    int Height(){return Height(root);}  //获取二叉树的高度(深度)
    void PreOrderN();                   //前序遍历算法非递归实现
    void InOrderN();                    //中序遍历算法非递归实现
    void Parent(int x);                 //寻找双亲结点
    void DelX(int x,int flag){DelX(root,x,flag);}   //删除值为x的结点的子树
    void LevelOrder();                  //层序遍历
};

BiTree.cpp

#include "BiTree.h"

BiNode *BiTree::Creat()
{
    //可以采用广义表的方法去建立二叉树
    // if(IsRoot==0)
    // {
    //     cout<<"请输入根结点数据域(0表示空)"
    // }
    BiNode *bt;
    int da; //临时变量
    cout << "请输入该结点数据域(0表示空):";
    cin >> da;
    if (da == 0)
    {
        bt = nullptr;
    }
    else
    {
        bt = new BiNode;
        bt->data = da;
        bt->lchild = Creat(); //递归调用创建结点方法
        bt->rchild = Creat(); //递归调用创建结点方法
    }
    return bt; //返回总树及每一棵子树的根节点root
}

void BiTree::Release(BiNode *bt)
{
    //析构函数的调用过程
    cout << "析构" << endl;
    //和后续遍历的思想一致
    //左子树  右子树  根节点

    //递归终止条件
    if (bt == nullptr)
    {
        return;
    }
    else
    {
        Release(bt->lchild); //递归调用释放左子树
        Release(bt->rchild); //递归调用释放右子树
        delete bt;
    }
    cout << "析构成功" << endl;
}

void BiTree::PreOrder(BiNode *bt)
{
    //递归调用的终止条件
    if (bt == nullptr)
    {
        return;
    }
    else
    {
        //前序遍历: 根节点  左子树  右子树
        cout << bt->data << " "; //输出数据域
        PreOrder(bt->lchild);
        PreOrder(bt->rchild);
    }
}

void BiTree::InOrder(BiNode *bt)
{
    //中序遍历
    if (bt == nullptr)
    {
        return;
    }
    else
    {
        //中序遍历: 左子树  根节点 右子树
        InOrder(bt->lchild);
        cout << bt->data << " ";
        InOrder(bt->rchild);
    }
}

void BiTree::PostOrder(BiNode *bt)
{
    //后序遍历
    if (bt == nullptr)
    {
        return;
    }
    else
    {
        //后序遍历:左子树 右子树 根节点
        PostOrder(bt->lchild);
        PostOrder(bt->rchild);
        cout << bt->data << " ";
    }
}

int BiTree::Size(BiNode *bt)
{
    if (bt == nullptr)
    {
        return 0;
    }
    return 1 + Size(bt->lchild) + Size(bt->rchild);
}

int BiTree::Leaf(BiNode *bt)
{
    //递归实现
    if (bt == nullptr)
    {
        return 0;
    }
    if (bt->lchild == nullptr && bt->rchild == nullptr)
    {
        return 1;
    }
    return Leaf(bt->lchild) + Leaf(bt->rchild); //递归调用子函数,求子树中叶子结点的个数
}

int BiTree::Height(BiNode *bt)
{
    //求二叉树的高度(深度)
    if (bt == nullptr)
    {
        return 0;
    }
    int i = Height(bt->lchild);
    int j = Height(bt->rchild);
    return i < j ? j + 1 : i + 1;
}

void BiTree::PreOrderN()
{
    //前序遍历算法的非递归实现
    BiNode *bt = this->root;
    BiNode *S[100]; //顺序栈 直接基于数组实现
    int top = -1;   //顺序栈初始化
    while (bt != nullptr || top != -1)
    {
        //终止条件:是空树且栈为空栈
        while (bt != nullptr)
        {
            cout << bt->data << " ";
            S[++top] = bt; //根指针入栈
            bt = bt->lchild;
        }
        if (top != -1)
        {
            bt = S[top--];
            bt = bt->rchild;
        }
    }
}

void BiTree::InOrderN()
{
    //中序遍历算法的非递归实现
    BiNode *bt = this->root;
    BiNode *S[100]; //顺序栈 直接基于数组实现
    int top = -1;   //顺序栈初始化
    while (bt != nullptr || top != -1)
    {
        //终止条件:是空树且栈为空栈
        while (bt != nullptr)
        {
            S[++top] = bt; //根指针入栈
            bt = bt->lchild;
        }
        if (top != -1)
        {
            bt = S[top--];
            cout << bt->data << " ";
            bt = bt->rchild;
        }
    }
}

void BiTree::Parent(int x)
{
    //int重载
    this->target = x; //更改靶子的值
    Parent(root);     //开始寻找双亲
}

void BiTree::Parent(BiNode *bt)
{
    if (bt != nullptr)
    {
        if (bt->lchild != nullptr && bt->lchild->data == target)
        {
            cout << "值为" << target << "的结点的双亲结点的值为" << bt->data << endl;
            return;
        }
        if (bt->rchild != nullptr && bt->rchild->data == target)
        {
            cout << "值为" << target << "的结点的双亲结点的值为" << bt->data << endl;
            return;
        }
        else
        {
            Parent(bt->lchild);
            Parent(bt->rchild);
        }
    }
}

int BiTree::DelX(BiNode *bt, int x, int flag)
{
    //删除值为x的结点的子树  递归方法实现  flag为标志 用于记录并判断
    if (bt == nullptr)
    {
        return 0;
    }
    else
    {
        if (bt->data == x) //如果当前结点的值为x,则更改标志,并将标志向下传递
        {
            flag = 1;
        }

        int leftFlag = DelX(bt->lchild, x, flag);  //递归左子树
        int rightFlag = DelX(bt->rchild, x, flag); //递归右子树

        if (1 == flag) //若flag为1,则说明其先祖结点有值为x,该子结点需要被删除
        {
            if (bt->data == x) //若其数据域为x,则应向上传递标志为1,以便赋空
            {
                return 1;
            }
            delete bt;
        }
        else
        {
            if (1 == leftFlag)
            {
                bt->lchild = nullptr; //从子结点接受收的信息,即如果其子结点为x,需要将其指针域赋空
            }

            if (1 == rightFlag)
            {
                bt->rchild == nullptr; //从子结点接受收的信息,即如果其子结点为x,需要将其指针域赋空
            }
        }
    }
    return 0;
}

void BiTree::LevelOrder()
{
    //层序遍历 基于队列
    BiNode *Q[100]; //所需队列
    BiNode *q = nullptr;

    int front = -1, rear = -1; //队列初始条件
    if (root == nullptr)
    {
        //空树不操作
        return;
    }

    Q[++rear] = root; //根指针入队
    while (front != rear)
    {
        //遍历条件:当队列非空时
        q = Q[++front]; //出队
        cout << q->data << " ";
        if (q->lchild != nullptr)
            Q[++rear] = q->lchild;
        if (q->rchild != nullptr)
            Q[++rear] = q->rchild;
    }
}

main.cpp

#include<iostream>
#include"BiTree.h"
using namespace std;

int main()
{
    cout<<"基于链式存储结构的二叉树"<<endl;
    BiTree b1;
    cout<<"前序遍历(递归):";
    b1.PreOrder();
    cout<<endl;

    cout<<"前序遍历(非递归):";
    b1.PreOrderN();
    cout<<endl;

    cout<<"中序遍历(递归):";
    b1.InOrder();
    cout<<endl;

    cout<<"中序遍历(非递归):";
    b1.InOrderN();
    cout<<endl;

    cout<<"后序遍历:";
    b1.PostOrder();
    cout<<endl;

    cout<<"层序遍历:";
    b1.LevelOrder();
    cout<<endl;

    int fl=0;
    b1.DelX(2,fl);
    cout<<"前序遍历(递归):";
    b1.PreOrder();
    cout<<endl;

    b1.Parent(4);
    cout<<"当前二叉树共有"<<b1.Leaf()<<"个叶子结点"<<endl;
    cout<<"当前二叉树共有"<<b1.Size()<<"个结点"<<endl;
    cout<<"当前二叉树的高度(深度)为"<<b1.Height()<<endl;
    system("pause");
    return 0;
}

测试

main.cpp

int main()
{
    cout<<"基于链式存储结构的二叉树"<<endl;
    BiTree b1;
    cout<<"前序遍历(递归):";
    b1.PreOrder();
    cout<<endl;

    cout<<"前序遍历(非递归):";
    b1.PreOrderN();
    cout<<endl;

    cout<<"中序遍历(递归):";
    b1.InOrder();
    cout<<endl;

    cout<<"中序遍历(非递归):";
    b1.InOrderN();
    cout<<endl;

    cout<<"后序遍历:";
    b1.PostOrder();
    cout<<endl;

    cout<<"层序遍历:";
    b1.LevelOrder();
    cout<<endl;

    int fl=0;
    b1.DelX(2,fl);
    cout<<"前序遍历(递归):";
    b1.PreOrder();
    cout<<endl;

    b1.Parent(4);
    cout<<"当前二叉树共有"<<b1.Leaf()<<"个叶子结点"<<endl;
    cout<<"当前二叉树共有"<<b1.Size()<<"个结点"<<endl;
    cout<<"当前二叉树的高度(深度)为"<<b1.Height()<<endl;
    system("pause");
    return 0;
}

我们创建这样的一棵树

image-20211026212602746

image-20211026212134006

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值