【数据结构】二叉树(二)

news2024/11/25 2:40:38

目录

一、二叉树链式结构及实现

 1、二叉树的结构

 2、二叉树的遍历

   2.1 前序遍历

   2.2 中序遍历

   2.3 后序遍历

   2.4 层序遍历

 3、二叉树链式结构的实现

   3.1 创建一个节点

   3.2 二叉树节点个数 

   3.3 二叉树叶子节点个数

   3.4 二叉树的高度

   3.5 二叉树第k层节点个数

   3.6 二叉树查找值为x的节点

   3.7 判断二叉树是否是完全二叉树

二、二叉树基础oj练习题

 1、单值二叉树

   1.1 题目说明 

   1.2 题目解析

 2、检查两棵树是否相同

   2.1 题目说明

   2.2 题目解析

 3、对称二叉树

   3.1 题目说明

   3.2 题目解析

 4、二叉树的前序遍历

   4.1 题目说明

   4.2 题目解析

 5、二叉树的中序遍历

   5.1 题目说明

   5.2 题目解析

 6、二叉树的后序遍历

   6.1 题目说明

   6.2 题目解析

 7、另一颗树的子树

   7.1 题目说明

   7.2 题目解析

 


一、二叉树链式结构及实现

 1、二叉树的结构

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

二叉树链式结构类型,这种是节点类型,包括了左右孩子节点,和该节点的数据值。

 2、二叉树的遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉 树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。下面给出了4中遍历方法。

   2.1 前序遍历

先是访问根节点,然后访问左子树,最后访问右子树。

//二叉树前序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

   2.2 中序遍历

先是访问左子树,然后访问根节点,最后访问右子树。

//二叉树中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

   2.3 后序遍历

先是访问左子树,然后访问右子树,最后访问根节点。

//二叉树后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

   2.4 层序遍历

层序遍历,就是按照二叉树每一层的节点进行访问。

思路:需要创建一个队列,首先将根节点放入队列,然后当队列不为空时,就出队头节点,如果队头节点的左子树不为空,它的左子树节点就入队列,如果队头节点的右子树不为空,它的右子树节点就入队列,依次循环,直到队列里面没有节点,此时,层序遍历结束。

//二叉树层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		printf("%d ", front->data);
		QueuePop(&q);
		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}
	}
	printf("\n");
	QueueDestroy(&q);
}

 3、二叉树链式结构的实现

   3.1 创建一个节点

要想实现二叉树链式结构,首先要创建节点,创建完节点将其初始化。

//创建一个节点
BTNode* BuyBTNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	node->data = x;
	node->left = node->right = NULL;
	return node;
}

   3.2 二叉树节点个数 

此处给了两种方法,第一种就是通过全局变量,每到一个结点总数就++。第二种方法就是简化了一下,左子树节点个数+右子树节点个数+根节点。

//二叉树节点个数
int size = 0;
int TreeSize1(BTNode* root)
{
	if (root == NULL)
		return 0;
	
	//前序遍历
	size++;
	TreeSize1(root->left);
	TreeSize1(root->right);
    return size;
}

//二叉树节点个数
int TreeSize2(BTNode* root)
{
	return root == NULL ? 0 : TreeSize2(root->left) + TreeSize2(root->right) + 1;
}

   3.3 二叉树叶子节点个数

计算叶子节点个数,需要分情况讨论,如果根节点为空时,就等于0,如果根节点的左右子树都为空时,叶子节点个数就为1,剩下就是根节点的左右子树都不为空的情况了,此时遍历左子树和右子树计算叶子节点个数。

//二叉树叶子节点个数
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;
	
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

   3.4 二叉树的高度

二叉树的高度就是算左右两边子树的最大高度。需要递归到最后一层,然后再+当前节点高度。

//二叉树的高度或深度(后序遍历)
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

   3.5 二叉树第k层节点个数

同样需要递归根节点的左右子树,看看每一层左右子树有多少个节点,然后相加即可。

//二叉树第k层的节点个数 k >= 1
int TreeKLevelSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	//k > 1 子树的k-1
	return TreeKLevelSize(root->left, k - 1) + TreeKLevelSize(root->right, k - 1);
}

   3.6 二叉树查找值为x的节点

二叉树查找节点的方法也是用的递归,首先先判断这颗二叉树是否为空,如果为空,就不存在x,如果根节点处的值等于x,就找到了,如果没有,就向下进行,先遍历左子树,再遍历右子树,直到找到x。

//二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
		return ret1;

	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
		return ret2;
	return NULL;
}

   3.7 判断二叉树是否是完全二叉树

思路:和上面层序遍历一致,同样要是用队列,还是一层一层的将节点入队列,出队列,当出队列遇到空节点时,停止入队列。然后判断队列中是否都是空节点,若都是空节点,则为完全二叉树,否则不为完全二叉树。

//判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front == NULL)
		{
			break;
		}
		else
		{
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
	}
	//出到空以后,如果后面全是空,则是完全二叉树
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

二、二叉树基础oj练习题

 1、单值二叉树

   1.1 题目说明 

    题目链接:单值二叉树

    如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时,才返回 true;否则返回 false

 

   1.2 题目解析

    思路:如果树为空,则说明是单值二叉树,如果它的左子树不为空且左子树的节点值和根节点值不相等,则返回false,如果它的右子树不为空且右子树的节点值和根节点值不相等,则返回false。

bool isUnivalTree(struct TreeNode* root){
    if(root == NULL)
    return true;

    if(root->left && root->left->val != root->val)
        return false;
    
    if(root->right && root->right->val != root->val)
        return false;

    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

 2、检查两棵树是否相同

   2.1 题目说明

   题目链接:相同的树

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

 

 

   2.2 题目解析

   思路:判断根,左子树、右子树是否相同——1.判断结构是否相同     2.判断val是否相同。

首先有两种特殊情况,就是如果根节点 p 和 根节点 q 都为空,说明这两棵树为相同的树,如果根节点 p 和 根节点 q ,有一个为空,说明这两棵树不相同。

如果 节点 p 的值不等于节点 q 的值,很明显这两棵树不相同,最后遍历 p 和 q 的左右子树。 

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p == NULL && q == NULL)
        return true;
    if(p == NULL || q == NULL)
        return false;
    if(p->val != q->val)
        return false;
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

 3、对称二叉树

   3.1 题目说明

   题目链接:对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

 

   3.2 题目解析

   思路:为了方便判断这棵树是否是轴对称,我们先写一个函数,判断其轴对称。

轴对称函数其实和上面判断两棵树是否相同一样,就是在最后递归的时候,需要 root1 的左子树和root2 的右子树进行判断是否是相同的,或者是 root1 的右子树和 root2 的左子树进行判断是否是相同的,如果相同,则说明是对称二叉树。

bool _isSymmetric(struct TreeNode* root1,struct TreeNode* root2)
{
    if(root1 == NULL && root2 == NULL)
        return true;
    
    if(root1 == NULL || root2 == NULL)
        return false;

    if(root1->val != root2->val)
        return false;

    return _isSymmetric(root1->left,root2->right) && _isSymmetric(root1->right,root2->left);
}

bool isSymmetric(struct TreeNode* root){
    return !root || _isSymmetric(root->left,root->right);
}

 4、二叉树的前序遍历

   4.1 题目说明

   题目链接:二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

   4.2 题目解析

   思路1:这种方法是递归形式,先是编写一个前序遍历的算法,前序遍历的访问顺序是根节点,然后是左子树,最后是右子树。

class Solution {
public:
    void preorde(TreeNode* root,vector<int>& ret)
    {
        if(root == nullptr)
            return;
        ret.push_back(root->val);
        preorde(root->left,ret);
        preorde(root->right,ret);
        
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ret;
        preorde(root,ret);
        return ret;
    }
};

   思路2:这种方法是非递归形式,这种思路是将一棵树分为了两部分:(1)左路节点;(2)左路节点的右子树。这里面用到的,它的作用就是为了访问左路节点的右子树。

 

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> s;
        vector<int> v;
        TreeNode* cur = root;
        while(cur || !s.empty())
        {
            while(cur)
            {
                v.push_back(cur->val);
                s.push(cur);
                cur = cur->left;
            }
            TreeNode* top = s.top();
            s.pop();
            cur = top->right;
        }
        return v;
    }
};

 5、二叉树的中序遍历

   5.1 题目说明

   题目链接:二叉树的中序遍历

   给你二叉树的根节点 root ,返回它节点值的 中序 遍历。

   5.2 题目解析

   思路1:用递归方式,先是编写一个中序遍历的算法,中序遍历的访问顺序是左子树,然后是根节点,最后是右子树。

class Solution {
public:
    void inorder(TreeNode* root, vector<int>& ret) {
        if (root == NULL) 
            return;
        inorder(root->left, ret);
        ret.push_back(root->val);
        inorder(root->right, ret);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        inorder(root, ret);
        return ret;
    }
};

    思路2: 用的是非递归方式,将一颗二叉树分为两个部分:(1)左路节点;(2)左路节点的右子树。和上面前序遍历的非递归方式一样,不同的是进入 v 的顺序不同。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> s;
        vector<int> v;
        TreeNode* cur = root;
        while(cur || !s.empty())
        {
            while(cur)
            {
                s.push(cur);
                cur=cur->left;
            }
            TreeNode* top = s.top();
            s.pop();
            v.push_back(top->val);

            cur = top->right;
        }
        return v;
    }
};

 6、二叉树的后序遍历

   6.1 题目说明

   题目链接:二叉树的后序遍历

   给你二叉树的根节点 root ,返回它节点值的 后序 遍历。

   6.2 题目解析

    思路1:用递归方式,先是编写一个后序遍历的算法,后序遍历的访问顺序是左子树,然后是右子树,最后是根节点。

class Solution {
public:
    void postorder(TreeNode *root, vector<int> &ret) 
    {
        if (root == nullptr) 
        {
            return;
        }
        postorder(root->left, ret);
        postorder(root->right, ret);
        ret.push_back(root->val);
    }
    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> ret;
        postorder(root, ret);
        return ret;
    }
};

   思路2:用非递归方式,将一颗二叉树分为两个部分:(1)左路节点;(2)左路节点的右子树。注意:假设第一次取到6时,上一个访问的节点是左子树的根4,第二次取到6时,上一个访问的节点是右子树的根7。所以有了另一个限制条件 top->right == prev 。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> s;
        vector<int> v;
        TreeNode* cur = root;
        TreeNode* prev = nullptr;
        while(cur || !s.empty())
        {
            while(cur)
            {
                s.push(cur);
                cur = cur->left;
            }
            TreeNode* top = s.top();
            //1.右为空 或者 右子树已经访问过了(上一个访问的节点是右子树的根),可以访问根节点
            if(top->right == nullptr || top->right == prev)
            {
                v.push_back(top->val);  
                s.pop(); 
                prev = top;
            }
            else
            {
                //访问左路节点右子树  ---- 子问题
                cur = top->right;
            }
        }
        return v;
    }
};

 7、另一颗树的子树

   7.1 题目说明

   题目链接:另一棵树的子树

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

   7.2 题目解析

   思路:三步走:1.判断它们是不是相同的树    2.判断subRoot是不是root的左子树  3.判断subRoot是不是root的右子树。

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    if (p == NULL && q == NULL)
        return true;
     //其中一个为空
    if (p == NULL || q == NULL)
        return false;
    if (p->val != q->val)
        return false;
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    if(root == NULL)
        return false;
    if(isSameTree(root,subRoot))
        return true;
    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

   

   


本文要是有不足的地方,欢迎大家在下面评论,我会在第一时间更正。 

老铁们,记着点赞加关注!!!  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/630338.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库管理-第八十二期 EMCC升级教程(20230607)

数据库管理 2023-06-07 第八十二期 EMCC升级教程1 升级EMCC1.1 升级概览1.2 拷贝相关文件1.3 升级OPatch1.4 升级OMSPatcher1.5 升级WLS1.6 升级OMS 2 升级Agent2.1 升级概览2.2 拷贝相关文件2.3 安装或升级AgentPatcher2.4 升级agent 3 升级Oracle数据库ASH包总结 第八十二期 …

什么时候适合加一层?

加一层能解决问题&#xff1a; 为什么加一层能解决问题&#xff1f; 什么时候适合加一层&#xff1f; 销售说不吵的&#xff0c; 道路检测说没有超标。 业主就是睡不着。 吃瓜群众说你为啥买那边的房子。 销售说开发商骗他&#xff0c;他也是受害者。 结果没问题&#xff0…

CSS 样式语言 选择器

CSS介绍 层叠样式表&#xff0c;是一种样式表语言&#xff0c;用来描述HTML和XML文档的呈现。随着HTML的发展&#xff0c;为了满足页面设计者的要求&#xff0c;HTML添加了很多显示功能&#xff0c;但是随着这些功能的增加&#xff0c;使得HTML越来越杂乱&#xff0c;HTML 页面…

「企业安全架构」EA874:安全需求,愿景、原则和流程

安全需求愿景 在开始任何安全架构工作之前&#xff0c;定义安全需求是很重要的。这些需求应该受到业务上下文和通用需求远景文档的影响。下面是一个图表&#xff0c;它显示安全需求是企业信息安全体系结构中业务上下文的一部分。 图1 安全需求远景&#xff08;SRV&#xff09;有…

Android系统原理性问题分析 - 系统 Root 的实现原理

声明 在Android系统中经常会遇到一些系统原理性的问题&#xff0c;在此专栏中集中来讨论下。Android低版本时经常听说Root系统&#xff0c;随着Android版本的升高&#xff0c;提Root的人越来越少了。不过我在系统开发时也有客户提出为系统Root的需求&#xff0c;所以在这里分析…

【产品经理】用户增长方法论

在做用户增长为核心的产品运营推广前&#xff0c;我们应从几个方面入手——打造核心功能点、转化方式要清晰、用户反馈与转化、传播渠道要合适、建立病毒式传播规则。 2017年&#xff0c;以营销见长的可口可乐公司将设置了24年之久的首席营销官&#xff08;CMO&#xff09;撤销…

[Maven高级]->近万字文章带你深入了解Maven

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;JavaEE ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&…

已经安装高版本CUDA的条件下bitsandbytes发现低版本的CUDA SETUP: Detected CUDA version 100解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Zabbix 配置钉钉报警

如有错误&#xff0c;敬请谅解&#xff01; 此文章仅为本人学习笔记&#xff0c;仅供参考&#xff0c;如有冒犯&#xff0c;请联系作者删除&#xff01;&#xff01; 1. 创建服务群【手机钉钉】|【电脑钉钉】- 右上角【】-【发起群聊】-【选人建群】/选择不同的群类型创建&…

数据库信息速递 甲骨文与微软合作,在Azure上推出数据库服务

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

Linux搭建配置jdk开发环境

因为ZooKeeper、Hadoop和Spark等大数据应用的运行需要Java环境的支持&#xff0c;所以需要我们来安装配置一下jdk环境。 安装步骤如下&#xff1a; 下载JDK 访问Oracle官网下载Linux x64操作系统的JDK安装包jdk-8u161-linux-x64.tar.gz。 上传JDK安装包 通过SecureCRT远程连接…

chatgpt赋能python:Python的数据存储:理解Python的内存管理机制

Python的数据存储&#xff1a;理解Python的内存管理机制 Python是一种高级编程语言&#xff0c;广泛用于开发Web应用程序、机器学习和数据科学等。作为一门动态语言&#xff0c;Python的内存管理机制是其优点之一。这篇文章将探讨Python如何内部存储数据&#xff0c;介绍Pytho…

pytorch ddp 范例

pytorch ddp 范例&#xff1a; ################ ## main.py文件 import argparse from tqdm import tqdm import torch import torchvision import torch.nn as nn import torch.nn.functional as F # 新增&#xff1a; import torch.distributed as dist from torch.nn.paral…

从零开始手搓一个STM32与机智云的小项目——GPIO的输入输出

文章目录 前言GPIO简介GPIO的命名与数量GPIO的功能STM32F1 GPIO的寄存器 库函数开发搭建库函数的工程查看原理图WACK_UP输入按键继电器输出138控制流水灯 代码编写库函数简介GPIO输出模式控制继电器通过138控制ledGPIO实现按键输入的操作编写逻辑代码 实物效果 总结 前言 上一…

Redis学习总结(二)

AOF 为什么是在执行完命令之后记录日志&#xff1f; 关系型数据库&#xff08;如 MySQL&#xff09;通常都是执行命令之前记录日志&#xff08;方便故障恢复&#xff09;&#xff0c;而 Redis AOF 持久化机制是在执行完命令之后再记录日志。AOF 记录日志过程为什么是在执行完命…

如何让GPT不再胡说八道

相信我们大部分人在使用GPT的时候&#xff0c;会发现GPT经常在胡言乱语、回复错误的答案等情况&#xff0c;甚至有的内容牛头不对马嘴&#xff0c;直接开始编造&#xff0c;例如下面案例&#xff1a; 我&#xff1a; 周树人是谁 GPT&#xff1a;周树人 (1897年-1975年) &…

独立开发变现周刊(第90期):自学开发了一个36万美元/年的ChatGPT应用

分享独立开发、产品变现相关内容&#xff0c;每周五发布。 目录 1、ChatGPT-Midjourney: 开源 ChatGPTMidjourney 网页应用2、PLExtension: 一个图床上传浏览器扩展3、EasySpider: 一个可视化爬虫软件4、BibiGPT: 音视频 AI 一键总结 & 对话5、自学的程序员开发了一个36万美…

【i阿极送书——第四期】《ChatGPT时代:ChatGPT全能应用一本通》

系列文章目录 作者&#xff1a;i阿极 作者简介&#xff1a;数据分析领域优质创作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f4c1;评论&#x1f4d2;…

MongoDB集群和安全

目录 副本集-Replica Sets简介副本集的三个角色副本集架构目标副本集的创建主节点副本节点仲裁节点初始化配置副本集和主节点查看副本集的配置内容查看副本集状态添加副本从节点添加仲裁从节点副本集的数据读写操作 主节点的选举原则完整的连接字符串 分片集群-Sharded Cluster…

spring杂记

1、springboot是如何解析yml配置文件中的 tomcat配置&#xff0c;并将其赋值给 tomcat的 重要类 ServerProperties。该类为解析yml文件中的server配置 下面我们主要看看是怎样将 端口号 port 赋值给tomcat的 找到port属性&#xff0c;点击getter方法 发现调用该方法的地方为 …