C++进阶:搜索树

目录

  • 1. 二叉搜索树
    • 1.1 二叉搜索树的结构
    • 1.2 二叉搜索树的接口及其优点与不足
    • 1.3 二叉搜索树自实现
      • 1.3.1 二叉树结点结构
      • 1.3.2 查找
      • 1.3.3 插入
      • 1.3.4 删除
      • 1.3.5 中序遍历
  • 2. 二叉树进阶相关练习
    • 2.1 根据二叉树创建字符串
    • 2.2 二叉树的层序遍历I
    • 2.3 二叉树层序遍历II
    • 2.4 二叉树最近公共祖先结点
    • 2.5 二叉树搜索与双向链表
    • 2.6 从前序与中序遍历序列构造二叉树
    • 2.7 从中序与后序遍历序列构造二叉树
    • 2.8 二叉树前序遍历(非递归)
    • 2.9 二叉树中序遍历(非递归)
    • !!!3.10 二叉树后序遍历(非递归)

1. 二叉搜索树

1.1 二叉搜索树的结构

  1. 搜索二叉树中的所有结点都满足
    <1> 若左子树不为空,则其所有结点的键值都小于父结点
    <2> 若右子树不为空,则其所有结点的键值都大于父节点
    <3> 左右子树都为二叉搜索树

在这里插入图片描述

1.2 二叉搜索树的接口及其优点与不足

  1. 搜索二叉树的功能接口
    <1> 数据插入(Insert)
    <2> 数据删除(Erase)
    <3> 数据查寻(Find)
    <4> 中序遍历(InOrder)
  1. 二叉搜索树的优点:
    <1> 正如其名,此种数据存储结构,尤其擅长数据搜索,其进行数据搜索的效率极高。
    <2> 在其结构为近似完全二叉树或满二叉树的情况时,其的搜索效率可以达到O( l o g N logN logN)
    <3> 当以中序遍历的方式遍历整棵搜索树时,得到的数据即为升序序列

在这里插入图片描述

  1. 二叉搜索树的不足:
    <1> 根据二叉搜索树的插入逻辑,当数据以完全升序或降序插入时,会使得二叉树退化为单枝结构,此种结构下其搜索效率也退化为O(N)

在这里插入图片描述

1.3 二叉搜索树自实现

1.3.1 二叉树结点结构

  1. 搜索树结点:由左右孩子结点指针与key组成
  2. 搜索树:由根节点与类方法构成
template<class T>
struct BinarySearchNode
{typedef BinarySearchNode<T> BSNode;BSNode* _left;BSNode* _right;T _key;BinarySearchNode(T key):_left(nullptr),_right(nullptr),_key(key){}
};template<class T>
class BinarySearchTree
{
public:typedef BinarySearchNode<T> BSNode;//查找bool Find(T key);//插入bool Insert(T key);//删除bool Erase(T key);//中序遍历void InOrder();private:BSNode* _root = nullptr;
};

1.3.2 查找

  1. 查找实现:在一颗搜索树中搜寻一个数据是否存在
  2. 查找逻辑:
    <1> 若查找值小于当前结点的key值,向左搜寻,向左孩子查找
    <2> 若查找值大于当前结点的key值,向右搜寻,向右孩子查找
    <3> 查找遍历至空结点,则证明搜索树中不存在此值
//非递归
bool Find(T key)
{BSNode* cur = _root;while (cur){if (key < cur->_key){cur = cur->_left;}else if (key > cur->_key){cur = cur->_right;}else{return true;}}return false;
}//递归
bool _FindR(BSNode* cur, T key)
{if (cur == nullptr){return false;}if (key < cur->_key){return _FindR(cur->_left, key);}else if (key > cur->_key){return _FindR(cur->_right, key);}else{return true;}//补全返回路径assert(true);return -1;
}bool FindR(T key)
{return _FindR(_root, key);
}

1.3.3 插入

  1. 搜寻插入位置:
    <1> key小向左
    <2> key大向右
    <3> 直至遍历到空
  2. <1> 若遇key相同的结点,停止插入,返回false
    <2> 遍历至空,创建结点,链接结点
//非递归
bool Insert(T key)
{//特殊处理根结点插入if (_root == nullptr){_root = new BSNode(key);return true;}BSNode* cur = _root;BSNode* parent = nullptr;while (cur){if (key < cur->_key){parent = cur;cur = cur->_left}else if (key > cur->_key){parent = cur;cur = cur->_right;}else{return false;}}//确定插入位置if (key < parent->_key){parent->_left = new BSNode(key);}else{parent->_right = new BSNode(key);}return true;
}//递归
bool _InsertR(BSNode*& cur, T key)
{//存在单子树的情况,导致段错误//传引用if (cur == nullptr){cur = new BSNode(key);return true;}if (key < cur->_key){return _InsertR(cur->_left, key);}else if (key > cur->_key){return _InsertR(cur->_right, key);}else{return false;}assert(true);return false;
}bool InsertR(T key)
{if (_root == nullptr){_root = new BSNode(key);return true;}return _InsertR(_root, key);
}

1.3.4 删除

  1. 删除结点后,不能破坏搜索树的结构
  2. 删除不同类型结点的场景,删除逻辑:
    <1> 叶子结点,直接删除,父节点链接指针置空
    <2> 单子树结点,托孤,即,将自己的子树链接给父结点
    <3> 双子树结点,寻找key值最接近的结点(左子树的最右结点,右子树的最左结点),值替换被删除的结点,而后删除被替换的结点
  1. 叶子结点
    在这里插入图片描述
  2. 单子树结点
    在这里插入图片描述
  3. 双子树结点
    在这里插入图片描述
//非递归
bool Erase(T key)
{BSNode* cur = _root;BSNode* parent = nullptr;while (cur){//查找到删除结点的位置if (key < cur->_key){parent = cur;cur = cur->_left;}else if (key > cur->_key){parent = cur;cur = cur->_right;}else//找到了{//叶子结点与单子树结点的删除//可以合并共用一套逻辑if (cur->_left == nullptr || cur->_right == nullptr)//叶子结点/单子树{//根结点特殊处理if (cur == _root){if (cur->_left){_root = cur->_left;}else{_root = cur->_right;}delete cur;}else//普通结点{//托孤if (cur->_left)//左单子树{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;}else//右单子树/叶子节点{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;}}return true;}else//双子树{//寻找右子树的最左结点BSNode* RightParent = cur;BSNode* RightMin = cur->_right;while (RightMin->_left){RightParent = RightMin;RightMin = RightMin->_left;}//值替换cur->_key = RightMin->_key;//删除被替换结点//删除结点的左孩子一定为空,所以按照右子树结点处理//托孤if (RightMin == RightParent->_left){RightParent->_left = RightMin->_right;}else{RightParent->_right = RightMin->_right;}//删除delete RightMin;return true;}}}//未找到return false;
}//递归
bool _EraseR(BSNode*& cur, T key)
{if (cur == nullptr){return false;}//寻找删除结点if (key < cur->_key){return _EraseR(cur->_left, key);}else if (key > cur->_key){return _EraseR(cur->_right, key);}else//找到了{//使用传引用后,对操作的优化if (cur->_left == nullptr || cur->_right == nullptr)//叶子结点/单子树结点{BSNode* del = cur;if (cur->_left){cur = cur->_left;}else{cur = cur->_right;}delete del;return true;}else//双子树{//寻找右子树的最左结点BSNode* RightMin = cur->_right;while (RightMin->_left){RightMin = RightMin->_left;}//值替换cur->_key = RightMin->_key;//值替换后,删除结点传值改变//转化为单子树删除,调用单子树删除处理_EraseR(cur->_right, cur->_key);}}assert(true);return false;
}

1.3.5 中序遍历

void _InOrder(BSNode* cur)
{if (cur == nullptr){return;}//左根右_InOrder(cur->_left);cout << cur->_key << " ";_InOrder(cur->_right);
}void InOrder()
{_InOrder(_root);cout << endl;
}

2. 二叉树进阶相关练习

2.1 根据二叉树创建字符串

  1. 题目信息:
    在这里插入图片描述
  2. 题目连接:
    根据二叉树创建字符串
class Solution 
{
public:void _tree2str(string& str, TreeNode* cur){if(cur == nullptr){return;}//字符串转字符串stoi(整形),stod(浮点型)str += to_string(cur->val);//除左空右不空的情况外,其余省略if(cur->left || cur->right){str += "(";_tree2str(str, cur->left);str += ")";}if(cur->right){str += "(";_tree2str(str, cur->right);str += ")";}}string tree2str(TreeNode* root) {string ret;//递归_tree2str(ret, root);return ret;}
};

2.2 二叉树的层序遍历I

  1. 题目信息:
    在这里插入图片描述
  2. 题目连接:
    二叉树的层序遍历I
  3. 思路:levelsize计数
class Solution
{
public:vector<vector<int>> levelOrder(TreeNode* root){//levelsize计数vector<vector<int>> ret;queue<TreeNode*> q;int levelsize = 1;q.push(root);//可能为空树if(root == nullptr){return ret;}while (!q.empty()){vector<int> count;while (levelsize--){//记录TreeNode* top = q.front();q.pop();count.push_back(top->val);//插入新结点if (top->left)q.push(top->left);if (top->right)q.push(top->right);}levelsize = q.size();ret.push_back(count);}return ret;}
};

2.3 二叉树层序遍历II

  1. 题目信息:
    在这里插入图片描述
  2. 题目连接:
    二叉树层序遍历II
  3. 思路:反转自上至下的层序遍历
class Solution 
{
public:vector<vector<int>> levelOrderBottom(TreeNode* root) {//全部压栈,无法判断层//得出自上至下的序列,然后逆置vector<vector<int>> ret;if(root == nullptr){return ret;}queue<TreeNode*> q;int levelsize = 1;q.push(root);while(!q.empty()){vector<int> count;while(levelsize--){TreeNode* cur = q.front();q.pop();count.push_back(cur->val);if(cur->left)q.push(cur->left);if(cur->right)q.push(cur->right);}levelsize = q.size();ret.push_back(count);}reverse(ret.begin(), ret.end());return ret;}
};

2.4 二叉树最近公共祖先结点

  1. 题目信息:
    在这里插入图片描述
  2. 二叉树最近公共祖先结点
  3. 思路:
    <1> 方法1:p与q一定分别在祖先结点的左侧与右侧,祖先结点可能是自己
    <2> 方法2:栈记录遍历路径,路径上的所有祖先结点
//方法1:
class Solution 
{
public:bool SearchNode(TreeNode* cur, TreeNode* search){if(cur == nullptr){return false;}if(cur == search){return true;}return SearchNode(cur->left, search) || SearchNode(cur->right, search);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {bool qInleft = false;bool qInright = false;bool pInleft = false;bool pInright = false;TreeNode* cur = root;while(cur){//可能最近祖先结点是自己if(cur == p){pInleft = pInright = true;}else if(SearchNode(cur->left, p)){pInleft = true;pInright = false;}else{pInright = true;pInleft = false;}if(cur == q){qInleft = qInright = true;}else if(SearchNode(cur->left, q)){qInleft = true;qInright = false;}else{qInright = true;qInleft = false;}if((pInleft && qInright) || (pInright && qInleft))break;else if(pInleft && qInleft)cur = cur->left;elsecur = cur->right;}return cur;}
};//方法2:
class Solution 
{
public:bool PreOrder(TreeNode* cur, TreeNode* search, stack<TreeNode*>& count){if(cur == nullptr){return false;}count.push(cur);if(cur == search){return true;}if(!PreOrder(cur->left, search, count) && !PreOrder(cur->right, search, count)){count.pop();}else{return true;}assert(true);return false;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//栈记录遍历路径,所有祖先结点//到达指定结点的路径只有一条//深度优先遍历stack<TreeNode*> p_st;stack<TreeNode*> q_st;PreOrder(root, p, p_st);PreOrder(root, q, q_st);//路径上的相交结点while(p_st.size() != q_st.size()){if(p_st.size() > q_st.size())p_st.pop();elseq_st.pop();}while(p_st.top() != q_st.top()){p_st.pop();q_st.pop();}return p_st.top();}
};

2.5 二叉树搜索与双向链表

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    二叉搜索树与双向链表
  3. 思路:记录前置结点,中序遍历,注意调整指针链接的时机
class Solution 
{
public:void InOrder(TreeNode* cur, TreeNode*& pre){if(cur == nullptr){return;}InOrder(cur->left, pre);cur->left = pre;if(pre)pre->right = cur;pre = cur;InOrder(cur->right, pre);}TreeNode* Convert(TreeNode* pRootOfTree) {if(pRootOfTree == nullptr){return nullptr;}TreeNode* pre = nullptr;InOrder(pRootOfTree, pre);while(pRootOfTree->left){pRootOfTree = pRootOfTree->left;}return pRootOfTree;}
};

2.6 从前序与中序遍历序列构造二叉树

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    从前序与中序遍历序列构造二叉树
  3. 思路:根据根分割出左右子树,区域分割,引用
class Solution 
{
public:TreeNode* buildNode(vector<int>& preorder, vector<int>& inorder, int& i, int left, int right){if(left > right){return nullptr;}//在中序中找到需构建结点int j = 0;while(inorder[j] != preorder[i]){j++;}//根左右//构建TreeNode* newnode = new TreeNode(preorder[i++]);//分割域,判断,构建左孩子newnode->left = buildNode(preorder, inorder, i, left, j - 1);//分割域,判断,构建右孩子newnode->right = buildNode(preorder, inorder, i, j + 1, right);return newnode;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int i = 0;return buildNode(preorder, inorder, i, 0, inorder.size() - 1);}
};

2.7 从中序与后序遍历序列构造二叉树

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    从中序与后序遍历序列构造二叉树
  3. 思路:区域分割判断,引用,逆向遍历,根右左
class Solution 
{
public:TreeNode* buildNode(vector<int>& inorder, vector<int>& postorder, int& i, int left, int right){if(left > right){return nullptr;}int j = 0;while(inorder[j] != postorder[i]){j++;}TreeNode* newnode = new TreeNode(postorder[i--]);newnode->right = buildNode(inorder, postorder, i, j + 1, right);newnode->left = buildNode(inorder, postorder, i, left, j - 1);return newnode;}TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {//逆向遍历,根右左int i = postorder.size() - 1;return buildNode(inorder, postorder, i, 0, postorder.size() - 1);}
};

2.8 二叉树前序遍历(非递归)

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    二叉树前序遍历
  3. 思路:根左右,插入右子树时就将根删除,栈记录
class Solution 
{
public:vector<int> preorderTraversal(TreeNode* root) {//非递归,前序遍历,根左右vector<int> ret;TreeNode* cur = root;stack<TreeNode*> st;while(cur || !st.empty()){while(cur){st.push(cur);ret.push_back(cur->val);cur = cur->left;}TreeNode* top = st.top();st.pop();cur = top->right;}return ret;}
};

2.9 二叉树中序遍历(非递归)

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    二叉树中序遍历
  3. 思路:插入时机,删除时插入,左右根
class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {//中序,左右根vector<int> ret;stack<TreeNode*> st;TreeNode* cur = root;//插入时机,删除时插入while(cur || !st.empty()){while(cur){st.push(cur);cur = cur->left;}TreeNode* top = st.top();st.pop();ret.push_back(top->val);cur = top->right;}return ret;}
};

!!!3.10 二叉树后序遍历(非递归)

  1. 题目信息:
    在这里插入图片描述
  2. 题目链接:
    二叉树后续遍历
  3. 思路:二次遍历时删除,删除时插入,何时删除
class Solution 
{
public:vector<int> postorderTraversal(TreeNode* root) {//左右根vector<int> ret;stack<TreeNode*> st;TreeNode* cur = root;TreeNode* pre = nullptr;while(cur || !st.empty()){//左while(cur){st.push(cur);cur = cur->left;}//根TreeNode* top = st.top();//cur = st.top();if(top->right == nullptr || pre == top->right)//if(cur->right == nullptr || pre == cur->right){st.pop();pre = top;//pre = cur;ret.push_back(top->val);//ret.push_back(cur->val);}else{//右,死循环cur = top->right;//cur调整错误//cur = cur->right;}}return ret;}
};

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

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

相关文章

一、MinIO基本知识

MinIO基本知识 一、简介1.许可 二、部署1.Docker部署1.1 部署容器 1.2 MinIO页面访问1.3 创建Bucket![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6c8aa92975f146b691f1f36ce1033e7c.png) 三、Python-API1.安装包2.Bucket、Object概念3.Bucket-API4.MinIOClient-…

C++修炼之路之多态--多态的条件与例外,重载+重写+重定义

目录 前言 一&#xff1a;构成多态的条件及一些特殊情况&#xff08;前提是构成父子类&#xff09; 1.多态是在不同的继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的结果 2.两个条件 3.三同的两个例外 1.协变---返回值类型可以不同&#xff0c;但必…

c++ qt6.5 打包sqlite组件无法使用,尽然 也需要dll支持!这和开发php 有什么区别!

运行 程序会默认使用当前所在文件夹中的 dll 文件&#xff0c;若文件不存在&#xff0c;会使用系统环境变量路径中的文件&#xff1b;又或者是需要在程序源代码中明确指定使用的 dll 的路径。由于我安装 Qt 时将相关 dll 文件路径都添加到了系统环境变量中&#xff0c;所以即使…

【R语言】混合图:小提琴图+箱线图

{ggstatsplot} 是 {ggplot2} 包的扩展&#xff0c;用于创建图形&#xff0c;其中包含信息丰富的绘图本身中包含的统计测试的详细信息。在典型的探索性数据分析工作流程中&#xff0c;数据可视化和统计建模是两个不同的阶段&#xff1a;可视化通知建模&#xff0c;而建模又可以建…

MapReduce工作流程(Hadoop3.x)

MapReduce 是一种用于并行处理大规模数据集的——编程模型和处理框架。它通常用于分布式计算环境中&#xff0c;如Apache Hadoop。 工作流程 1. 切分阶段&#xff08;Splitting&#xff09;&#xff1a; 数据集被分成多个数据块&#xff0c;每个数据块的大小通常在64MB到12…

kaggle 泰坦尼克使用xgboost 得分0.73684

流程 导入所要使用的包引入kaggle的数据集csv文件查看数据集有无空值填充这些空值提取特征分离训练集和测试集调用模型 导入需要的包 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarni…

zabbix自定义监控、自动发现和注册以及代理设置

前言 监控项的定制和新设备的注册往往需要大量手动操作&#xff0c;这会导致维护成本的增加和监控效率的降低。本文将介绍如何利用 Zabbix 的自定义功能&#xff0c;实现监控项的动态发布和新设备的自动注册以及代理设置、从而简化运维工作并实现更高效的监控管理。 Zabbix 监…

【大模型开源篇1】彦宏您怎么看LLaMA3的开源

Meta LLaMA是Meta公司开源的大模型&#xff0c;作为大模型开源界得鼻祖&#xff0c; 刚刚发布LLaMA3。从ChatGPT 拉开了大模型竞赛的序幕&#xff0c;Meta 选择了开源&#xff0c;至此大模型也开始百花齐放的时期&#xff0c;但是开源模型一直无法超过必源模型&#xff0c;如今…

EA包图上嵌套的包位置不对

Extreme 2024-4-11 11:36 我从工具栏把一个包拖在另一个包里面&#xff0c;可是项目树上两个包的位置并列&#xff0c;拖了几次结果都一样。我的目的是做一个多层级的包图&#xff0c;是不是&#xff08;EA&#xff09;不能在图上做&#xff1f; UMLChina潘加宇 确实是这样&a…

Python可视化数据分析-饼状图

一、前言 饼状图&#xff08;Pie Chart&#xff09;是一种常用的数据可视化图表&#xff0c;用于展示数据中各部分的占比关系。Python 中有多种库可以用于绘制饼状图&#xff0c;比较常用的包括 matplotlib、pyecharts和 plotly 等。 二、使用 matplotlib 绘制饼状图 import…

必应bing搜索国内广告投放开户价格?

搜索引擎广告作为精准引流的重要手段之一&#xff0c;受到了众多企业的青睐&#xff0c;其中微软旗下的必应搜索&#xff08;Bing&#xff09;&#xff0c;以其独特的市场定位和用户群体&#xff0c;成为了不可忽视的广告投放平台。对于想要在中国市场利用必应搜索进行广告投放…

局域网无法连接怎么办?

局域网连接是我们日常生活和工作中常用的方式之一&#xff0c;但有时我们可能会遇到局域网无法连接的问题。这给我们的工作和生活带来了很大的困扰。本文将介绍局域网无法连接的常见原因&#xff0c;并推荐一款名为【天联】的组网产品&#xff0c;它能够解决不同地区间的局域网…

Google Earth Engine 洪水制图 - 使用 Sentinel-1 SAR GRD

Sentinel-1 提供从具有双极化功能的 C 波段合成孔径雷达 (SAR) 设备获得的信息。该数据包括地面范围检测 (GRD) 场景,这些场景已通过 Sentinel-1 工具箱进行处理,以创建经过校准和正射校正的产品。该集合每天都会更新,新获得的资产会在可用后两天内添加。 该集合包含所有 G…

Delphi Firemonkey使用TVertScrollbox自定义列表数据

界面布局设置如下 创建一个过程添加新项目 procedure TForm1.AddItem(name: string; age: Integer); varlayout: TLayout; begin// 设置姓名标签的文本Label3.Text : name;// 设置年龄标签的文本Label4.Text : IntToStr(age);// 克隆 Layout1&#xff0c;并将克隆得到的对象赋值…

FastJson2中FastJsonHttpMessageConverter找不到类问题

问题描述 如果你最近也在升级FastJson到FastJson2版本&#xff0c;而跟我一样也遇到了FastJsonHttpMessageConverter找不到类问题以及FastJsonConfig找不到问题&#xff0c;那么恭喜你&#xff0c;看完本文&#xff0c;安装完fastjson2、fastjson2-extension、fastjson2-exte…

STM32H743驱动SD卡(1)

本文内容参考&#xff1a; STM32——SDIO的学习&#xff08;驱动SD卡&#xff09;&#xff08;理论篇&#xff09;-CSDN博客 STM32个人笔记-SDIO接口-CSDN博客 STM32-(40)&#xff1a;SD卡与SDIO-CSDN博客 【STM32】使用SDIO进行SD卡读写&#xff08;一&#xff09;-初步认…

使用python-can和cantools实现arxml报文解析、发送和接收的完整指南

文章目录 背景一、硬件支持二、环境准备1、python解释器安装2、python库安装 三、 收发案例四、 方法拓展1、canoe硬件调用2、回调函数介绍 结论 背景 在汽车行业中&#xff0c;CAN (Controller Area Network) 总线是用于车辆内部通信的关键技术。arxml文件是一种用于描述CAN消…

【数据结构】算法效率揭秘:时间与空间复杂度的较量

前言 在计算机科学中&#xff0c;时间复杂度和空间复杂度是衡量算法性能的两个重要指标。它们分别表示算法在执行过程中所需的时间和空间资源。了解这两个概念有助于我们评估和比较不同算法的优劣&#xff0c;从而选择更合适的算法解决问题~ 欢迎关注个人主页&#xff1a;逸狼 …

.github/workflows Actions为项目构建增加手动CI 构建按钮

在Github CI项目的时候&#xff0c; 一般是有push的时候才触发CI构建任务&#xff0c; 今天介绍一种通过 on workflow_dispatch 来增加手动CI构建按钮的方法。 CI构建任务代码示例 .github/workflows/ci.yml name: CIon:push:branches: [develop]pull_request:branches: [dev…

社区论坛小圈子小程序源码系统:自定义小程序管理社区圈子软件圈子系统系统开发-做社区圈子丨圈子论坛社区交友系统开源版小程序源码丨

简述 移动互联网的快速发展&#xff0c;微信小程序作为一种新型的应用形态&#xff0c;已经深入到人们的生活中。特别是对于社区论坛类应用&#xff0c;小程序版本可以更好地满足用户快速、便捷获取信息的需求。下面给大家分享一款社区论坛小圈子小程序源码系统。 在这个信息…