C++数据结构学习笔记(二)根据输入字符构造二叉树并进行前序遍历,中序遍历,后序遍历,层序遍历(链表)

文章介绍了如何使用链式存储结构实现二叉树,包括定义节点结构体BiNode和二叉树类BiTree,提供了构造函数、析构函数以及前序、中序、后序和层序遍历的方法。代码示例使用C++语言,利用字符串表示二叉树的扩展二叉树前序遍历序列来构建树结构。
摘要由CSDN通过智能技术生成

                 强烈建议小白去B站搜索:懒猫老师


        二叉树可以通过顺序存储结构、链式存储结构、二维数组、邻接表的结构来存储,本文为较为简单直观,容易理解的链式存储结构的实现 。二叉链表的结构如图所示。

         首先定义一个节点结构体BiNode,data为数据域(可以改为模板类,能够兼容所有数据类型,此处使用char类型只做简单实现),lchild和rchild分别指向左右孩子。

struct BiNode
{
    char data;
    BiNode* lchild;
    BiNode* rchild;
};

        然后定义二叉树类BiTree,包含有参、无参构造函数,析构函数,以及四种遍历函数。定义的root根节点为私有成员变量,所以此处public的下的函数是不能直接对root进行访问的,public的函数再次调用private中的函数去对二叉树进行各种操作。这么写的好处是让类完全封装起来,只留下外部调用接口,安全性更高(我也不太懂,自己感觉的)。

class BiTree
{
private:
    BiNode* root;//指向根节点的头指针
public:
    BiTree(string &s) { root = Creat(root,s); };//构造函数,建立一颗二叉树
    BiTree() { root = Creat(root); };//构造函数,建立一颗二叉树
	~BiTree(){ Release(root);};//析构函数
    void PreOrder() { PreOrder(root); };//前序遍历二叉树
    void InOrder() { InOrder(root); };  //中序遍历二叉树
    void PostOrder() { PostOrder(root); };//后序遍历二叉树
    void LeverOrder();                     //层序遍历二叉树
private:
    BiNode* Creat(BiNode* bt);
    BiNode* Creat(BiNode* bt, string& s);//构造函数调用
    void Release(BiNode* bt);//析构函数调用
    void PreOrder(BiNode* bt);//前序遍历函数调用
    void InOrder(BiNode* bt);//中序遍历函数调用
    void PostOrder(BiNode* bt);//后序遍历函数调用
};

        无参构造函数直接返回空树,有参构造函数通过Public中的BiTree()调用的时候只需要有一个string类型变量s做参数即可,s为字符串。s为所需要二叉树的扩展二叉树的前序遍历序列。(为了建立一颗二叉树,将二叉树中的每个节点的空指针引出一个虚节点,其值为一个特定值,如“#”,以标识其为空,把这样处理后的二叉树称为原二叉树的扩展二叉树。)

        s传入到构造函数中,用迭代器取出字符串中的首个字符存入到ch中并删掉s的首个字符(意思就是挨个取),首先判断传入字符是否为“#”,若为“#”则说明该节点为空,直接返回。节点不为空的时候创建新节点并为data域赋值,然后递归调用Creat()依次构造左右子树。

//无参构造函数调用
BiNode* BiTree::Creat(BiNode* bt)
{
    bt = NULL;
    return bt;
}
//有参构造函数调用
BiNode* BiTree::Creat(BiNode* bt,string &s)
{
    string::iterator it = s.begin();
    char ch = *it;
    s.erase(0, 1);
    if (ch == '#')
        bt = NULL;
    else
    {
        bt = new BiNode;
        bt->data = ch;
        bt->lchild = Creat(bt->lchild,s);
        bt->rchild = Creat(bt->rchild,s);
    }
    cout << ch;
    return bt;
}

        前中后序遍历通过递归实现(也可以通过非递归实现,递归比较简单好理解) ,思想基本都一样。以前序遍历为例,传入参数为根节点,首先判断根节点是否为空,若为空则说明为空树(第二次递归调用时说明该节点为空,可以理解为空子树);若不为空则首先读取数据域,然后再递归依次读取左右子树。中序、后续同理,只是读取顺序有变化。

void BiTree::PreOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        cout << bt->data;
        PreOrder(bt->lchild);
        PreOrder(bt->rchild);
    }
}

void BiTree::InOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        InOrder(bt->lchild);
        cout << bt->data;
        InOrder(bt->rchild);
    }
}

void BiTree::PostOrder(BiNode* bt)
{
    if (bt == NULL)
        return;
    else
    {
        PostOrder(bt->lchild);
        PostOrder(bt->rchild);
        cout << bt->data;
    }
}

        层序遍历通过队列来实现,首先建立一个存取数据类型为BiNode的队列 ,用于暂存节点。遍历开始也是首先判断是否为空树,若不为空树则节点入队列。当队列不为空时,首先将队列的头节点——即最先入队的节点出队,输出该节点信息,然后判断该节点是否有左右子树,若有左右子树则依次入队。由于队是先进先出,所以能够实现按层从左到右读取。如果还是理解不了再次强烈建议B站观看懒猫老师视频!!!

void BiTree::LeverOrder()
{
    queue<BiNode*> q;
    if (this->root == NULL)
        return;
    q.push(this->root);
    while (!q.empty())
    {
        BiNode* q1 = q.front();
        q.pop();
        cout << q1->data;
        if (q1->lchild != NULL)
            q.push(q1->lchild);
        if (q1->rchild != NULL)
            q.push(q1->rchild);
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值