320二叉树笔记

本文深入介绍了二叉树这一重要数据结构,包括其定义、创建、遍历方法(如先序、中序、后序和层次遍历),以及如何求解二叉树的高度、叶子节点数量等问题。

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

二叉树作为树的一种,是一种重要的数据结构

常见类型:创建一颗二叉树(先序,中序,后序)、遍历一颗二叉树(先序,中序,后序和层次遍历)、求二叉树中叶子节点的个数、求二叉树的高度、求二叉树中两个节点的最近公共祖先、打印和为某一值的全部路径、求某一节点是否在一个树中等等。

 

不妨先看一下几种常见的二叉树:

 

完全二叉树:若二叉树的高度是h,除第h层之外,其他(1~h-1)层的节点数都达到了最大个数,并且第h层的节点都连续的集中在最左边。想到点什么没?实际上,完全二叉树和堆联系比较紧密哈~~~

 

满二叉树:除最后一层外,每一层上的所有节点都有两个子节点,最后一层都是叶子节点。


结点类定义:


//二叉树的节点类
class BinTreeNode
{
private:
    int data;
    BinTreeNode *left,*right;          //定义左右子结点
public:
    //利用初始化列表完成data,left,rightn的初始化
    BinTreeNode(const int &item,BinTreeNode *lPtr = NULL,BinTreeNode *rPtr = NULL):data(item) ,left(lPtr),right(rPtr){};
    void set_data(int item)       //插入数据
    {
        data = item;
    }
    int get_data()const               //返回数据
    {
        return data;
    }
    void set_left(BinTreeNode *l)       //设置左子树
    {
        left = l;
    }
    BinTreeNode* get_left()const      //返回左子树
    {
        return left;
    }
    void set_right(BinTreeNode *r)      //设置右子树
    {
        right = r;
    }
    BinTreeNode* get_right()const     //返回右子树
    {
        return right;
    }
};

二叉树原型: 包含下面申明的所有函数


//二叉树
class BinTree
{
private:
    BinTreeNode *root;
public:
    BinTree(BinTreeNode *t = NULL):root(t){};    //初始化列表的构造函数
    ~BinTree(){delete root;};
    void set_root(BinTreeNode *t)         //设置根节点为形参里面的节点
    {
        root = t;
    }
    BinTreeNode* get_root()const          //返回根节点
    {  
        return root; 
    }
    //1.创建二叉树
    BinTreeNode* create_tree();
    //2.前序遍历
    void pre_order(BinTreeNode *r)const;
    //3.中序遍历
    void in_order(BinTreeNode *r)const;
    //4.后序遍历
    void post_order(BinTreeNode *r)const;
    //5.层次遍历
    void level_order(BinTreeNode *r)const;
    //6.获得叶子节点的个数
    int get_leaf_num(BinTreeNode *r)const;
    //7.获得二叉树的高度
    int get_tree_height(BinTreeNode *r)const;
    //8.交换二叉树的左右儿子
    void swap_left_right(BinTreeNode *r);
    //9.求两个节点pNode1和pNode2在以r为树根的树中的最近公共祖先
    BinTreeNode* get_nearest_common_father(BinTreeNode *r,BinTreeNode *pNode1,BinTreeNode *pNode2)const;
    //10.打印和为某一值的所有路径
    void print_rout(BinTreeNode *r,int sum)const;
    //11.判断一个节点t是否在以r为根的子树中
    bool is_in_tree(BinTreeNode *r,BinTreeNode *t)const;
};

创建一颗二叉树

 

创建一颗二叉树,可以创建先序二叉树,中序二叉树,后序二叉树。我们在创建的时候为了方便,不妨用‘#’表示空节点,这时如果先序序列是:6 4 2 3 # # # # 5 1 # # 7 # #,那么创建的二叉树如下:

//创建二叉树,这里不妨使用前序创建二叉树,遇到‘#’表示节点为空
BinTreeNode* BinTree::create_tree()
{
    char item;           //定义一个字符串item
    BinTreeNode *t,*t_l,*t_r;      //定义结点还有左右结点
    cin>>item;          //输入字符串
    if(item != '#')         //若字符串输入正确
    {
        BinTreeNode *pTmpNode = new BinTreeNode(item-48); //new一个节点空间
        t = pTmpNode;          //并让在开头定义的t=上一部的结点
        t_l = create_tree();       //在t的左边新建一棵树
        t->set_left(t_l);        //不懂???
        t_r = create_tree();
        t->set_right(t_r);
        return t;
    }
    else
    {
        t = NULL;
        return t;
    }
}


二叉树的遍历

二叉树的遍历分为:先序遍历,中序遍历和后序遍历,这三种遍历的写法是很相似的,利用递归程序完成也是灰常简单的:


//前序遍历
void BinTree::pre_order(BinTreeNode *r)const  //形参中给的是根节点
{
    BinTreeNode *pTmpNode = r;       //将根节点赋给pTmpNode
    if(pTmpNode != NULL)
    {
        cout<<pTmpNode->get_data()<<" ";   //前序就是前访问
        pre_order(pTmpNode->get_left());   //在再左子树访问
        pre_order(pTmpNode->get_right());  //递归调用
    }
}
//中序遍历
void BinTree::in_order(BinTreeNode *r)const
{
    BinTreeNode *pTmpNode = r;
    if(pTmpNode != NULL)
    {
        in_order(pTmpNode->get_left());
        cout<<pTmpNode->get_data()<<" ";
        in_order(pTmpNode->get_right());
    }
}
//后序遍历

层次遍历

层次遍历也是二叉树遍历的一种方式,二叉树的层次遍历更像是一种广度优先搜索(BFS)。因此二叉树的层次遍历利用队列来完成是最好不过啦,当然不是说利用别的数据结构不能完成。

//层次遍历
void BinTree::level_order(BinTreeNode *r)const
{
    if(r == NULL)
        return;
    deque<BinTreeNode*> q;    //定义一个双端队列q  
    q.push_back(r);            //将r放入队列q中
    while(!q.empty())      //一直循环到队列中没有元素
    {
        BinTreeNode *pTmpNode = q.front();  //将第一个队列中的元素赋给pTmpNode节点
        cout<<pTmpNode->get_data()<<" ";   //输出结果
        q.pop_front();            //将刚才那个第一个元素退出
        if(pTmpNode->get_left() != NULL)
        {
            q.push_back(pTmpNode->get_left());   //如果左不为空,则再加入
        }
        if(pTmpNode->get_right() != NULL)      //如果右不为空,则再加入
        {
            q.push_back(pTmpNode->get_right());
        }
    }
}

求二叉树中叶子节点的个数

树中的叶子节点的个数 = 左子树中叶子节点的个数 + 右子树中叶子节点的个数。利用递归代码也是相当的简单,易懂。


//获取叶子节点的个数
int BinTree::get_leaf_num(BinTreeNode *r)const
{
    if(r == NULL)//该节点是空节点,比如建树时候用'#'表示
    {
        return 0;
    }
    if(r->get_left()==NULL && r->get_right()==NULL)//该节点并不是空的,但是没有孩子节点
    {
        return 1;
    }
    //递归整个树的叶子节点个数 = 左子树叶子节点的个数 + 右子树叶子节点的个数
    return get_leaf_num(r->get_left()) + get_leaf_num(r->get_right());
                                 //就是1+1=2个叶子节点
}

求二叉树的高度

求二叉树的高度也是非常简单,不用多说:树的高度 = max(左子树的高度,右子树的高度) + 1 。

//获得二叉树的高度
int BinTree::get_tree_height(BinTreeNode *r)const
{
    if(r == NULL)//节点本身为空
    {
        return 0;
    }
    if(r->get_left()==NULL && r->get_right()==NULL)
                                  //叶子节点都不存在,只有根节点
    {
        return 1;
    }
    int l_height = get_tree_height(r->get_left());//??
    int r_height = get_tree_height(r->get_right());
    return l_height >= r_height ? l_height + 1 : r_height + 1; 
}

 判断一个节点是否在一颗子树中

可以和当前根节点相等,也可以在左子树或者右子树中。

//判断一个节点t是否在以r为根的子树中
bool BinTree::is_in_tree(BinTreeNode *r,BinTreeNode *t)const
{
    if(r == NULL)           //上面定义来看,r是根,t是目的节点
    {
        return false;        //如果r为空,说明为空树
    }
    else if(r == t)          //根节点就是要找的节点
    {
        return true;
    }
    else
    {
        bool has = false;    //定义一个名为has的bool值为false
        if(r->get_left() != NULL)
        {
            has = is_in_tree(r->get_left(),t);   //开始左循环
        }
        if(!has && r->get_right()!= NULL)  //开始右循环 
        {
            has = is_in_tree(r->get_right(),t);
        }
        return has;
    }
}        //相当于是一个前序遍历的比较算法







 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值