数据结构--二叉树_链式(下)
实现链式结构二叉树
链式结构就是由一个一个的节点组成。
⽤链表来表⽰⼀棵⼆叉树,即⽤链来指⽰元素的逻辑关系。 通常的⽅法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩⼦所在的链结点的存储地址。
二叉树节点结构的定义
typedef char BTDataType;
//二叉树结点结构的定义
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;
关于二叉树的遍历
想要实现链式结构二叉树,就一定要掌握二叉树的遍历相关的知识,二叉树的遍历分为前序遍历,中序遍历和后序遍历。
前序遍历:访问顺序为:根结点、左⼦树、右⼦树(根左右)。
假如,我现在有下图二叉树,那么前序遍历的顺序就为:
A,B,D,NULL,NULL,NULL,C,E,NULL,NULL,F,NULL,NULL.
我们从A开始遍历,A是根他的左孩子是B,但在左子树中,B也是根,继续往下遍历,他的左孩子是d,D与B同理,我们继续往下遍历NULL为空,然后我们就往上走,D的左孩子遍历完成后,我们遍历D的右孩子也是NULL,那么此时,对于D这颗左子树我们已经便利完成,再继续往上走B这颗子树的左孩子和根节点我们已经遍历完成,就剩下它的右孩子NULL,此时整个左子树我们都遍历完成了,再去遍历右子树。右子树与左子树同理,便利的顺序为C,E,BULL,NULL,F,NULL,NULL。如果大家还有不懂,可以在评论区问我,这里就不再赘述了。
中序遍历:访问顺序为:左⼦树、根结点、右⼦树(左根右)。
假如,我现在有下图二叉树,那么中序遍历的顺序就为:
NULL, D, NULL, B, NULL, A, NULL, E, NULL, C, NULL, F, NULL.
后序遍历:访问顺序为:左⼦树、右⼦树,根结点(左右根)。
假如,我现在有下图二叉树,那么后序遍历的顺序就为:
NULL, NULL, D, NULL, B, NULL, NULL, E, NULL, NULL, F, C, A.
了解二叉树的遍历后,我来代码实现一下。开启递归的暴力美学!
老规矩,我们创建三个项目分别是Tree.h,Tree.c,test.c
首先,我们先手动实现一个二叉树:
代码:test.c
//手动构造一棵二叉树
BTNode* CreateTree()
{BTNode* nodeA = buyNode('A');BTNode* nodeB = buyNode('B');BTNode* nodeC = buyNode('C');BTNode* nodeD = buyNode('D');BTNode* nodeE = buyNode('E');BTNode* nodeF = buyNode('F');nodeA->left = nodeB;nodeA->right = nodeC;nodeB->left = nodeD;nodeC->left = nodeE;nodeC->right = nodeF;return nodeA;
}
前序遍历代码实现:
//前序遍历 根左右
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}
前序遍历的过程:
前序遍历的顺序为根左右,我们首先要判断根是不是空,如果根为空我们就不需要遍历了,如果根不为空,我们就要先把根打印出来,打印完成后,我们就又要递归调用root->left,也就是B,B这个节点不为空,我们把B的左孩子D打印出来,打印完成后继续递归,D的左孩子,D的左孩子为空,就满足root=NULL这个条件,打印一下NULL,打印完成后return,return就意味函数栈帧将会释放,也就意味4这个代码执行完了,我们回到上一级3,D的左孩子打印完了,继续递归打印右孩子。此刻,D的左右孩子和它自己都已经打印完成,就意味着D这个函数已经调用完了,我们就要释放函数栈帧,继续向上走。回到2,继续打印B的右孩子(操作6),打印完NULL后,就要return,释放函数栈帧回到2,B的左右孩子和它自身已经打印完了,释放函数栈帧回到A,A的左孩子和它自身打印完了,继续打印它的右孩子C,所以这里的参数root就是C,C不为空,我们接下来打印C里面的数据。递归调用C,打印C的左孩子E,E不为空,我们就打印E里面的数据,E的左孩子为空,我们打印NULL,然后return 释放函数栈帧。然后再去递归E的右孩子,E的右孩子也是空,所以再打印一个NULL。E的左右孩子和它本身都打印成功后,释放函数栈帧,返回C,继续递归C的右孩子F,与E同理,递归完F后,释放函数栈帧回到C,C的全部内容也打印完成,现在要销毁函数栈帧,然后再回到A,A的全部内容也打印完成,也要销毁函数栈帧。A的函数栈帧销毁就意味着我们的遍历完成了,所有通过递归创建的的函数栈帧都销毁完了。
测试结果:
中序遍历代码实现:
//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%c ", root->data);InOrder(root->right);
}
遍历过程:
首先这里传过来的根节点A,判断A是不是空。不为空就要去递归A。A的左孩子就是是B这个节点,所以这里创建了一个B的函数栈帧,判断B的函数栈帧为空吗,不为空,那我们继续去调用。B的left就是D。所以这里我们创建了一个函数栈帧参数为D,,D不为空再继续去递归它的左孩子在这里创建新的函数栈帧,参数为NULL。在参数为NULL的函数栈帧中,参数为空我们就打印空。然后return当前函数栈帧被销毁。销毁之后我们回到根节点D,D的函数栈帧的左孩子我们已经递归完了,接下来我们要打印一下D,D打印完了之后,接下来我们要递归调用D的右孩子,那么D的右孩子为NULL,我们就打印一下NULL。打印完了之后要return也就意味着NULL这个函数栈帧我们已经调用完了。然后我们销毁这个函数栈帧,然后再继续回到D这个函数。D这个函数里面所有的代码都已经执行完了那么函数战争要销毁回到了B的函数栈帧。再去递归B的右孩子,我们又要去创建一个参数为NULL的函数栈帧,然后打印NULL,再继续return,销毁函数栈帧回到B。那么B所有内容我们已经递归完了,也就意味着这一行代码就已经执行完了,那么接下来我们要打印当前A节点里的值,然后再继续去递归A的右子树,那么A的的的右子树在这里创建了一个函数栈帧参数为C,C不为空我们就在这个函数栈帧里面继续递归它的左孩子。C的左孩子是E,我们就创建参数为E的函数栈帧,E不为空再继续递归它的左孩子,它的左孩子创建函数栈帧的参数NULL,那我们就打印NULL,然后再让它return,然后销毁NULL这个函数栈帧。在E这个函数栈帧中,它的左孩子已经递归完了,接下来是要打印根节点E。接下来是右孩子,继续递归创建函数栈帧为NULL,再打印NULL然后return,然后让函数栈帧消毁。E的全部内容递归完了,那么就要销毁它的函数栈帧,然后回到C,接下来递归它的右孩子F,F不为空,再继续创建函数栈帧参数NULL,为NULL我就打印NULL。然后直接return,销毁函数栈帧。F的左孩子我已经递归完了,接下来我们要打印一下当前节点里的值F, F打印完了之后,在F这个函数栈帧中继续递归它的它的右孩子,创建一个参数为NULL的函数栈帧然后打印NULL,直接return销毁函数栈帧。回到F,F的全部内容我已经打印完了,再继续往上回溯到C这个函数栈帧,C里面的所有内容都已经递归完成,再继续回溯到A这个函数栈帧中,A的全部内容也处理完了,销毁函数栈帧,至此整个递归完成。
测试结果:
后序遍历代码实现:
后续遍历的过程大家可以自己思考一下,有什么问题打在评论区。
//后序遍历--左右根
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%c ", root->data);
}
测试结果:
求二叉树结点的个数
求整个二叉树节点的个数只需要根节点+左子树的节点个数+右子树的节点个数。
左子树又是一颗子树,也分左右子树,所以左子树的节点个数也是 1+左子树的节点个数+右子树的节点个数。右子树同理。这就又是一个递归问题。
代码:
// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root) {if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
测试结果:
求二叉树叶子节点的个数
叶子节点:该节点的左孩子和右孩子都为空
我们依然可以把这个二叉树分成左右子树,然后依次求左子树叶子结点的个数和右子树叶子结点的个数,然后相加。还是使用递归。
代码:
// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
测试结果:
求二叉树第K层结点的个数
假设我们要找的是k=2层结点的个数。首先我们要判断根节点为不为空,不为空我们继续遍历, 我们可以递归让k--,找到我们要找的那一层。然后遍历,让左子树节点的个数+右子树节点的个数,就是第k层总的节点的个数。
代码:
// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
测试结果:
求二叉树的深度/高度
注意 : 不平衡的二叉树 的深度按照最大的深度计算 如下图 , 二者的深度都为3.
根节点的层次+左子树和右子树中最大的层次。
代码:
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root)
{if (root == NULL){return 0;}int leftDep = BinaryTreeDepth(root->left);int rightDep = BinaryTreeDepth(root->right);return 1 + (leftDep > rightDep ? leftDep : rightDep);
}
测试结果:
二叉树查找值为x的节点
首先我们需要判断根节点是否为空,不为空我们就进行遍历,使用上述讲过的哪种都可以,这里我们使用先序遍历。先遍历左子树,如果找到了就直接返回,如果没找到就继续遍历右子树。
代码:
// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* leftFind = BinaryTreeFind(root->left, x);if (leftFind){return leftFind;}BTNode* rightFind = BinaryTreeFind(root->right, x);if (rightFind){return rightFind;}return NULL;
}
测试结果:
二叉树的销毁
二叉树是由链表组成,而链表是由节点组成,所以我们销毁节点即可,那么我们用什么方法销毁节点呢?
我们可以使用前面讲的后序遍历,边遍历边销毁,那为什么不使用前序遍历或者后序遍历呢?
如果我们的根先被销毁了,是不是就不容易找到它的左右孩子啊,所以我们使用后序遍历。
代码:
// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root) {if (*root == NULL){return;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}
测试结果:
全部代码
Tree.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef char BTDataType;
//二叉树结点结构的定义
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;
//前序遍历
void PreOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后序遍历
void PostOrder(BTNode* root);
// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root);
// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root);
// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);
// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root);
Tree.c
#include"Tree.h"//前序遍历 根左右
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%c ", root->data);InOrder(root->right);
}
//后序遍历--左右根
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%c ", root->data);
}
// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root) {if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root)
{if (root == NULL){return 0;}int leftDep = BinaryTreeDepth(root->left);int rightDep = BinaryTreeDepth(root->right);return 1 + (leftDep > rightDep ? leftDep : rightDep);
}
// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* leftFind = BinaryTreeFind(root->left, x);if (leftFind){return leftFind;}BTNode* rightFind = BinaryTreeFind(root->right, x);if (rightFind){return rightFind;}return NULL;
}
// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root) {if (*root == NULL){return;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}
tese.c
#include"Tree.h"BTNode* buyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));node->data = x;node->left = node->right = NULL;return node;
}
//手动构造一棵二叉树
BTNode* CreateTree()
{BTNode* nodeA = buyNode('A');BTNode* nodeB = buyNode('B');BTNode* nodeC = buyNode('C');BTNode* nodeD = buyNode('D');BTNode* nodeE = buyNode('E');BTNode* nodeF = buyNode('F');nodeA->left = nodeB;nodeA->right = nodeC;nodeB->left = nodeD;nodeC->left = nodeE;nodeC->right = nodeF;return nodeA;
}
void test() {BTNode* root = CreateTree();//PreOrder(root);//InOrder(root);//PostOrder(root);//printf("size:%d\n", BinaryTreeSize(root));//printf("leaf size:%d\n", BinaryTreeLeafSize(root));//printf("K size:%d\n", BinaryTreeLevelKSize(root, 2));//printf("K size:%d\n", BinaryTreeLevelKSize(root, 3));//printf("depth:%d\n", BinaryTreeDepth(root));BTNode* find = BinaryTreeFind(root, 'Z');if (find == NULL){printf("未找到!\n");}else {printf("找到了!\n");}BinaryTreeDestory(&root);
}
int main() {test();return 0;
}
祝大家生活愉快。
相关文章:

数据结构--二叉树_链式(下)
实现链式结构二叉树 链式结构就是由一个一个的节点组成。 ⽤链表来表⽰⼀棵⼆叉树,即⽤链来指⽰元素的逻辑关系。 通常的⽅法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩⼦所在的链结点的存储…...
unity游戏开发之--人物打怪爆材料--拾进背包的实现思路
unity游戏开发之–人物打怪爆材料–拾进背包的实现思路 游戏实现:unity c# 1、敌人(怪物)的生命值和伤害系统 using UnityEngine; using System.Collections.Generic;public class Enemy : MonoBehaviour {[Header("基础属性")]…...
AWTK文件系统适配器更新-支持RT-Thread DFS POSIX接口
介绍 AWTK 文件系统适配器。 在嵌入式平台中,有时没有 POSIX 兼容的文件系统 API,需要把一些文件系统实现,包装成 AWTK 的 fs 接口。本项目提供一些常见文件系统的适配,目前支持的文件系统有: FATFS 主要用于访问 TF…...

C#如何快速获取P/Invoke方法签名
使用API函数已经好几年了,封装函数签名基本是参照MSDN上的文档,然后再做数据类型对应。 虽然有 pinvoke.net 这个网站,但基本很少使用。一方面是想多动手,另一方面是因为各种数据类型基本都用过了,都能自己在C#中 对应…...
CqEngine添加联合索引和复合唯一索引
一.实体类 Data public class CategoryT {private Integer id;private String oneCategory;private String twoCategory;private String createTime;private String updateTime;public String uniKey() {return oneCategory "/" twoCategory;} }二.集合 Suppress…...

基于matlab的SVPWM逆变器死区补偿算法仿真研究
背景介绍: 三相脉宽调制(pulse width modulation,PWM)电压源逆变器(voltage source inverter,VSI)的死区效应可导致电机相电压和相电流畸变、零电流钳位效应以及转矩和转速脉动,系统性能降低。为提高系统运行性能,对V…...

【网页设计】CSS 定位
目标 能够说出为什么要用定位能够说出定位的4种分类能够说出4种定位各自的特点能够说出为什么常用子绝父相布局能够写出淘宝轮播图布局能够说出显示隐藏的2种方式以及区别 1. 定位 1.1 为什么需要定位 提问: 以下情况使用标准流或者浮动能实现吗?1. …...
scala的属性访问权限
scala的属性访问权限有四种: 默认访问权限;protected访问权限;private访问权限;private[this]访问权限 package Test1104 //访问控制权限// 类的内部方法 伴生对象中的方法 类的外部(对象,访问)…...

QGIS:HCMGIS插件
插件GitHub地址:https://github.com/thangqd/HCMGIS。 以下对HCMGIS插件进行简单介绍,并演示如何进行地图数据下载。 插件简介 HCMGIS - Basemaps, Download OpenData, Batch Converter, VN-2000 Projections, and Field Calculation Utilities for QGI…...
Melty 主体流程图
┌───────────┐ │ 用户输入 │ └─────┬─────┘ │(自然语言或指令) │ ▼ ┌───────────┐ │ 自然语言处理 │ │ (NLU 模块)│ └─────┬─────┘ │ │ 解析用户意图 │ ▼ ┌─…...

【图像与点云融合教程(五)】海康相机 ROS2 多机分布式实时通信功能包
0. 前言 Github 仓库链接:Hikvision Camera ROS2 package 0.1 问题背景 上一篇[博客](【图像与点云融合教程(四)】海康相机 ROS2 功能包 - 古月居 (guyuehome.com))介绍了我开源的海康相机 ROS2 功能包,在本地机器上可以实时订…...

正则截取字符窜数字,字母,符号部分
Testvoid test20() {String str "BJRabG11325F9**0**";// 提取字母部分String letterPart str.replaceAll("[^a-zA-Z]", "");String noLetterPart str.replaceAll("[a-zA-Z]", "");System.out.println("字母部分&am…...
【ChatGPT】让ChatGPT生成跨语言翻译的精确提示
让ChatGPT生成跨语言翻译的精确提示 在跨语言交流中,为了确保翻译的准确性,生成精确的提示(Prompt)来指导ChatGPT翻译内容是至关重要的。无论是要处理复杂的技术术语、俚语,还是保持特定的语言风格,使用有…...

Vue3父传子
1. App.vue - 父组件 咱们先来看左边的 App.vue,它扮演的是“父亲”角色——你可以想象它是一位热心的老爸,手里拿着一条消息,正准备把这条消息送到“儿子”那里。 <script setup> // 这个 setup 就像一个神奇的开关,一开…...
使用VBA宏合并多个Excel文件的Sheet页
使用VBA宏合并多个Excel文件的Sheet页 在日常的Excel数据处理工作中,我们经常需要将多个Excel文件中的工作表合并到一个Excel文件中。这种操作可以极大地提高数据处理效率,但如果文件数量较多,手动合并会非常繁琐。本文将介绍如何使用VBA宏来…...
Anolis8防火墙安全设置
一、账号安全 1、禁止root远程登录 首先创建一个普通用户,然后修改系统配置禁止root登录,因为root作为系统默认的超级管理员,权限过大,日常操作使用易导致安全风险。 1.1、首先要建立一个新的登录用户 useradd username #增…...
标题:自动化运维:现代IT运维的革新力量
标题:自动化运维:现代IT运维的革新力量 随着信息技术的飞速发展,企业对于IT系统的依赖日益加深,运维工作的重要性也愈发凸显。传统的运维模式,往往依赖于人工操作,效率低下且容易出错,难以满足…...

无人机之姿态融合算法篇
无人机的姿态融合算法是无人机飞行控制中的核心技术之一,它通过将来自不同传感器的数据进行融合,以实现更加精确、可靠的姿态检测。 一、传感器选择与数据预处理 无人机姿态融合算法通常依赖于多种传感器,包括加速度计、陀螺仪、磁力计等。这…...

Redis系列---数据管理
目录标题 数据类型String优点缺点底层结构使用场景实际使用 List优点缺点底层结构使用场景实际使用 Hash优点缺点底层结构使用场景实际使用 Set优点缺点底层结构使用场景实际使用 Zset优点缺点底层结构使用场景实际使用 HyperLogLog优点缺点底层结构使用场景实际使用 GEO优点缺…...

【Linux系统编程】第四十二弹---多线程编程全攻略:涵盖线程创建、异常处理、用途、进程对比及线程控制
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、线程创建 2、线程异常 3、线程用途 4、进程 VS 线程 5、线程控制 5.1、创建和等待线程 1、线程创建 线程能看到进程的大…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...