【数据结构1-2】二叉树

树形结构不仅能表示数据间的指向关系,还能表示出数据的层次关系,而有很明显的递归性质。因此,我们可以利用树的性质解决更多种类的问题。

但是在平常的使用中,我们并不需要使用这么复杂的结构,只需要建立一个包含int right和int left的结构体即可,left和right用于指示该节点的左儿子和右儿子。


一、【P4913】二叉树深度(递归/层次遍历)

本题的重点在于二叉树的存储和二叉树的层次遍历。

1. 二叉树存储:考虑一个二叉树的每个节点都有两个子节点,所以我们可以考虑用一个结构体来存储。其中,leftright分别代表节点的左节点编号和右节点编号。

struct node {int left, right;
};
node tree[MAXN];

2. 二叉树层次遍历:我们可以从根节点出发,先递归遍历该节点的左节点,再递归遍历该节点的右节点。对于每个父亲节点,先比较左右子树的高度,然后选取较高的子树,将其深度加1,每次遍历更新子树的高度。当遍历到叶子节点后返回0(叶子节点的左右子树高度均为0)。

int maxDepth(int id)
{if (id == 0) return 0;return 1 + max(maxDepth(Tree[id].left), maxDepth(Tree[id].right));
}

AC代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>using namespace std;struct node
{int left;int right;
}Tree[1000005];int maxDepth(int id)
{if (id == 0) return 0;return 1 + max(maxDepth(Tree[id].left), maxDepth(Tree[id].right));
}int main()
{int n;	cin >> n;for (int i = 1; i <= n; i++){int a, b;	cin >> a >> b;Tree[i].left = a;Tree[i].right = b;}cout << maxDepth(1);}

二、【P1827】美国血统(前中后序遍历)

前序遍历、中序遍历和后序遍历是三种利用深度优先搜索遍历二叉树的方式。它们是在对节点访问的顺序有一点不同,其它完全相同。

需要注意的是下图中伪代码并未给出base case,即递归返回的条件。

AC代码:

先序遍历的特点是优先遍历根节点,所以整棵树的根应该会在inorder字符串的最开始出现;中序遍历的特点是优先遍历左子树,然后遍历根节点,所以我们可以根据中序遍历序列判断左右子树中包含哪些点。

以本题为例:

中序(inorder)遍历:ABEDFCHG;先序(preorder)遍历:CBADEFGH。

  1. 首先可以根据preorder判断C为根节点,然后依据inorder判断ABEDF为左子树中的节点,HG为右子树中的节点。
  2. 回到preorder序列,第二个节点是B,所以左子树的根节点为B,依据inorder序列可知A构成次级左子树,DEF构成次级右子树。
  3. 回到preorder序列,第三个节点是A,刚好是以B为根的子树的左子树的根;第四个节点是D,所以以B为根的子树的右子树的根为D。
  4. 以此类推,可以还原整棵树的情况。
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <set>using namespace std;struct TreeNode //建树
{char val;TreeNode* left;TreeNode* right;TreeNode() :val(0), left(nullptr), right(nullptr) {}TreeNode(char x) : val(x), left(nullptr), right(nullptr) {}TreeNode(char x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};//对preorder中的[s0,e0]部分操作,s1用于跟踪preorder序列中某个父亲节点
TreeNode* buildTree(string& preorder, map<char, int>& mp, int s0, int e0, int s1)
{if (s0 > e0) return nullptr;char mid = preorder[s1];int index = mp[mid]; //找到当前父亲节点在中序遍历inorder中的位置int left_length = index - s0; //左子树大小TreeNode* node = new TreeNode(mid);node->left = buildTree(preorder, mp, s0, index - 1, s1 + 1);node->right = buildTree(preorder, mp, index + 1, e0, s1 + 1 + left_length);return node;
}void PostOrder(TreeNode* tree)
{if (!tree) return;PostOrder(tree->left);PostOrder(tree->right);cout << tree->val;
}int main()
{string preorder, inorder;cin >> inorder >> preorder;map<char, int> mp;//使用map存储,便于搜索for (int i = 0; i < inorder.length(); i++)mp[inorder[i]] = i;TreeNode* res = buildTree(preorder, mp, 0, inorder.length() - 1, 0);PostOrder(res);
}

 由于需要通过preorder序列的节点,查询该点在inorder序列的位置,所以将inorder序列用map存储,实现O(1)量级的查询。

使用buildTree函数递归还原整棵树,然后使用postorder函数对树进行后序遍历,得到答案。


三、【P1229】遍历问题(前中后序遍历)

思路:给定inorder能确定树的具体结构,是因为可以确定子树是左子树还是右子树;而只给定preorder和postorder,则不能确定,这就是会出现不同树结构的原因。

只有前和后,那么主要问题就是没有办法处理只有一个子树的情况,因为这种情况下不知道子树究竟是这个节点的左子树还是右子树,也就是说其实这道题要判断遍历中存在着多少个只有一棵子树的情况。对于前,如果一个结点的下个结点等于后中对应结点的前一个结点的话,那么这个结点就是根节点且其只有一个子树。sum初始化为1,出现一个只有一棵子树的情况,就把sum*2(每次会出现两种不同的情况,分别是出现左子树和出现右子树)。

AC代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <cstring>
#include <queue>using namespace std;
const int INF = 0x7fffffff;int main()
{string preorder, postorder;cin >> preorder >> postorder;int sum = 1;for (int i = 0; i <= preorder.length() - 2; i++){for (int j = 0; j <= postorder.length() - 1; j++){if (preorder[i] == postorder[j] && preorder[i + 1] == postorder[j - 1]){sum *= 2;}}}cout << sum << endl;
}

四、【P1030】求先序序列(前中后序遍历)

首先,一点基本常识,给你一个后序遍历,那么最后一个就是根(如ABCD,则根为D),因为题目求先序,意味着要不断找根。

那么我们来看这道题方法:(示例)

中序ACGDBHZKX,后序CDGAHXKZB,首先可找到主根B;

那么我们找到中序遍历中的B,由这种遍历的性质,可将中序遍历分为ACGD和HZKX两棵子树,那么对应可找到后序遍历CDGA和HXKZ(从头找即可);从而问题就变成求:

  1. 中序遍历ACGD,后序遍历CDGA的树;
  2. 中序遍历HZKX,后序遍历HXKZ的树;

接着递归,按照原先方法,找到

1.子根A,再分为两棵子树;

2.子根Z,再分为两棵子树。

就按这样一直做下去(先输出根,再递归)。

模板概括为:

  • step1:找到根并输出
  • step2:将中序,后序各分为左右两棵子树;
  • step3:递归,重复step1,2;

AC代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <cstring>
#include <queue>using namespace std;
const int INF = 0x7fffffff;string inorder, postorder;void preorder(string in,string after)
{if (in.size() > 0){char ch = after[after.size() - 1];cout << ch;int k = in.find(ch);preorder(in.substr(0, k), after.substr(0, k)); //左子树preorder(in.substr(k + 1), after.substr(k, in.size() - k - 1));//从k开始,截取这么多个数}
}int main()
{cin >> inorder >> postorder;preorder(inorder, postorder);
}

将2,3,4三题进行比较,2的解题思路具有普适性,但是建树的过程相对复杂;4的解题思路较为清晰,但是缺点在于只能输出序列,并不能得到完整的树。


五、【P5076】简化二叉树(二叉搜索树)

参考:https://www.cnblogs.com/do-while-true/p/13566274.html 

但值得强调的是,二叉搜索树是一种低级的平衡二叉树,因为在最差情况下,可以会呈现链状结构,导致时间复杂度为O(n),而不是所需的O(logN)。因此,只需要了解即可,重点需要掌握的是平衡二叉树。

splay搜索树的几种操作:

(1)插入:x 是当前节点的下标,v 是要插入的值。要在树上插入一个 v 的值,就要找到一个合适 v 的位置,如果本身树的节点内有代表 v 的值的节点,就把该节点的计数器加 11 ,否则一直向下寻找,直到找到叶子节点,这个时候就可以从这个叶子节点连出一个儿子,代表 v 的节点。具体向下寻找该走左儿子还是右儿子是根据二叉搜索树的性质来的。

void add(int x,int v)
{tree[x].siz++;//如果查到这个节点,说明这个节点的子树里面肯定是有v的,所以siz++if(tree[x].val==v){//如果恰好有重复的数,就把cnt++,退出即可,因为我们要满足第四条性质tree[x].cnt++;return ;}if(tree[x].val>v){//如果v<tree[x].val,说明v实在x的左子树里if(tree[x].ls!=0)add(tree[x].ls,v);//如果x有左子树,就去x的左子树else{//如果不是,v就是x的左子树的权值cont++;//cont是目前BST一共有几个节点tree[cont].val=v;tree[cont].siz=tree[cont].cnt=1;tree[x].ls=cont;}}else{//右子树同理if(tree[x].rs!=0)add(tree[x].rs,v);else{cont++;tree[cont].val=v;tree[cont].siz=tree[cont].cnt=1;tree[x].rs=cont;}}
}

 (2)找前驱:x 是当前的节点的下标,val 是要找前驱的值,ans 是目前找到的比 val 小的数的最大值。找前驱的方法也是不断的在树上向下爬找具体节点,具体爬的方法可以参考代码注释部分。

int queryfr(int x, int val, int ans) {if (tree[x].val>=val){//如果当前值大于val,就说明查的数大了,所以要往左子树找if (tree[x].ls==0)//如果没有左子树就直接返回找到的ansreturn ans;else//如果不是的话,去查左子树return queryfr(tree[x].ls,val,ans);}else{//如果当前值小于val,就说明我们找比val小的了if (tree[x].rs==0)//如果没有右孩子,就返回tree[x].val,因为走到这一步时,我们后找到的一定比先找到的大(参考第二条性质)return (tree[x].val<val) ? tree[x].val : ans//如果有右孩子,,我们还要找这个节点的右子树,因为万一右子树有比当前节点还大并且小于要找的val的话,ans需要更新if (tree[x].cnt!=0)//如果当前节数的个数不为0,ans就可以更新为tree[x].valreturn queryfr(tree[x].rs,val,tree[x].val);else//反之ans不需要更新return queryfr(tree[x].rs,val,ans);}
}

(3)找后继:与找前驱同理,只不过需要反过来。

int queryne(int x, int val, int ans) {if (tree[x].val<=val){if (tree[x].rs==0)return ans;elsereturn queryne(tree[x].rs,val,ans);}else{if (tree[x].ls==0)return (tree[x].val>val)? tree[x].val : ans;if (tree[x].cnt!=0)return queryne(tree[x].ls,val,tree[x].val);elsereturn queryne(tree[x].ls,val,ans);}
}

(4)按值找排名:这里我们就要用到 siz 了,排名就是比这个值要小的数的个数再 +1,所以我们按值找排名,就可以看做找比这个值小的数的个数,最后加上 1 即可。

int queryval(int x,int val)
{if(x==0) return 0;//没有排名 if(val==tree[x].val) return tree[tree[x].ls].siz;//如果当前节点值=val,则我们加上现在比val小的数的个数,也就是它左子树的大小 if(val<tree[x].val) return queryval(tree[x].ls,val);//如果当前节点值比val大了,我们就去它的左子树找val,因为左子树的节点值一定是小的 return queryval(tree[x].rs,val)+tree[tree[x].ls].siz+tree[x].cnt;//如果当前节点值比val小了,我们就去它的右子树找val,同时加上左子树的大小和这个节点的值出现次数 //因为这个节点的值小于val,这个节点的左子树的各个节点的值一定也小于val 
}
//注:这里最终返回的是排名-1,也就是比val小的数的个数,在输出的时候记得+1

(5)按排名找值:排名为 n 的数在BST上是第 n 靠左的数。或者说排名为 n 的数的节点在BST中,它的左子树的 siz 与它的各个祖先的左子树的 siz 相加恰好 =n (这里相加是要减去重复部分)。

int queryrk(int x,int rk)
{if(x==0) return INF; if(tree[tree[x].ls].siz>=rk)//如果左子树大小>=rk了,就说明答案在左子树里 return queryrk(tree[x].ls,rk);//查左子树 if(tree[tree[x].ls].siz+tree[x].cnt>=rk)//如果左子树大小加上当前的数的多少恰好>=k,说明我们找到答案了 return tree[x].val;//直接返回权值 return queryrk(tree[x].rs,rk-tree[tree[x].ls].siz-tree[x].cnt);//否则就查右子树,同时减去当前节点的次数与左子树的大小 
}

AC代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <set>using namespace std;
const int INF = 0x7fffffff;struct node
{int val; //节点值int left, right; //左右子树int cnt; //计数器int siz; //子树大小
}tree[100005];
int cont = 0;//记录节点数量//初始化
void init()
{for (int i = 0; i < 100005; i++){tree[i].val = 0;tree[i].left = 0;tree[i].right = 0;tree[i].cnt = 0;tree[i].siz = 0;}
}//添加新点
void add(int x, int value) //当前节点为x,需要插入value
{tree[x].siz++; //肯定在x子树上,规模加一if (tree[x].val == value) //如果value刚好等于节点值,计数器加一即可{tree[x].cnt++;return;}if (tree[x].val > value) //如果x的值大于value,value只能放在x的左子树上{if (tree[x].left != 0)//如果左子树上有节点,递归查找add(tree[x].left, value);else//如果左子树上没有点,直接添加{cont++;tree[cont].val = value;tree[cont].siz = tree[cont].cnt = 1;tree[x].left = cont;}}else if (tree[x].val < value)//如果x的值小于value,value要放到x的右子树上{if (tree[x].right != 0)//如果右子树上有节点,递归查找add(tree[x].right, value);else//如果右子树上没有点,直接添加{cont++;tree[cont].val = value;tree[cont].siz = tree[cont].cnt = 1;tree[x].right = cont;}}
}//查找前驱
int query_front(int x, int value, int ans) //x 是当前的节点的下标,val 是要找前驱的值,ans 是目前找到的比val小的数的最大值。
{if (cont == 0) return -INF;if (tree[x].val >= value)//当前节点val大于所查value,到左子树查找{if (tree[x].left == 0) //左子树不存在,那么前驱为ansreturn ans;elsereturn query_front(tree[x].left, value, ans); //否则遍历左子树}else{if (tree[x].right == 0)//若无右孩子,说明当前点满足条件return (tree[x].val < value) ? tree[x].val : ans;else{if (tree[x].cnt != 0) //如果当前节点的个数不为0,ans就可以更新为tree[x].valreturn query_front(tree[x].right, value, tree[x].val);elsereturn query_front(tree[x].right, value, ans);}}
}//查找后继
int query_next(int x, int value, int ans)
{if (cont == 0) return INF;if (tree[x].val <= value){if (tree[x].right == 0)return ans;elsereturn query_next(tree[x].right, value, ans);}else{if (tree[x].left == 0)return (tree[x].val > value) ? tree[x].val : ans;else{if (tree[x].cnt != 0)return query_next(tree[x].left, value, tree[x].val);elsereturn query_next(tree[x].left, value, ans);}}
}//按值找排名
int val_to_rank(int x, int value)
{if (x == 0) return 0;if (value == tree[x].val)return tree[tree[x].left].siz;//比它小的数if (value < tree[x].val)return val_to_rank(tree[x].left, value);if (value > tree[x].val)return val_to_rank(tree[x].right, value) + tree[tree[x].left].siz + tree[x].cnt;//左子树上的所有点加上根上的点都小于value
}//按排名找值
int rank_to_val(int x, int rank)
{if (x == 0)return INF;if (tree[tree[x].left].siz >= rank) //如果小于x.val的数多于rank,那么该值一定在左子树上,递归查找return rank_to_val(tree[x].left, rank);if (tree[tree[x].left].siz + tree[x].cnt >= rank) //如果左子树上的点数+根上的节点数大于rank,且左子树上的点数小于rank,那么点x的值为所需值return tree[x].val;return rank_to_val(tree[x].right, rank - tree[tree[x].left].siz - tree[x].cnt); //否则在右子树上,要先将左子树+根上的点数减去
}int main()
{int q;	cin >> q;init();for (int i = 1; i <= q; i++){int op, v;cin >> op >> v;if (op == 1)cout << val_to_rank(1, v) + 1 << endl;else if (op == 2)cout << rank_to_val(1, v) << endl;else if (op == 3)cout << query_front(1, v, -INF) << endl;else if (op == 4)cout << query_next(1, v, INF) << endl;else{if (cont == 0){cont++;tree[cont].cnt = tree[cont].siz = 1;tree[cont].val = v;}elseadd(1, v);}}
}

六、【P1364】医院设置(BFS广搜)

广度优先搜索(breadth-first search, BFS)不同与深度优先搜索,它是一层层进行遍历的,因此需要用先入先出的队列而非先入后出的栈进行遍历。由于是按层次进行遍历,广度优先搜索时按照“广”的方向进行遍历的,也常常用来处理最短路径等问题。

在本题中,由于每个点都可以是原点(树根),因此采用树结构存储是行不通的,因为指针只能单方向指向。这里采用邻接矩阵的方式来存储树。

AC代码:

本题中只考虑每个点到根节点的距离,因此采用DFS和BFS均可。

由于BFS操作起来更直观,因此本题用普通图的形式存储树,枚举每个节点为根节点的情况,进行n遍BFS,然后每遍都进行答案的比较更新。

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <cstring>
#include <queue>using namespace std;
const int INF = 0x7fffffff;bool graph[105][105] = { 0 };
bool visit[105] = { 0 };
int value[105] = { 0 };struct node
{int num;int step; //用于存储某点到根节点的距离
};
int n;int BFS(int x) //以x为根对树进行BFS遍历
{memset(visit, 0, sizeof(visit)); queue<node> q;visit[x] = 1;node gen; gen.num = x, gen.step = 0;q.push(gen); //将树根节点入队int sum = 0;while (!q.empty()){node now = q.front();q.pop();for (int i = 1; i <= n; i++) //依次取出队列中的点,并找到与该点距离为1且未被访问过的点{if (graph[now.num][i] && !visit[i]){node next;next.num = i, next.step = now.step + 1; //更新选中点到根的距离visit[i] = 1;q.push(next);sum += value[i] * next.step; //该点的权重乘以与根的距离}}}return sum;
}int main()
{cin >> n;for (int i = 1; i <= n; i++){int w, u, v;cin >> w >> u >> v;value[i] = w;if (u != 0)graph[i][u] = graph[u][i] = 1;if (v != 0)graph[i][v] = graph[v][i] = 1;}int MinDis = INF;for (int i = 1; i <= n; i++){int tmp = BFS(i);if (tmp < MinDis)MinDis = tmp;}cout << MinDis << endl;
}

由于bfs每遍都是O(V+E)的,而这里特殊之处在于本身是个树,所以是n个节点和n-1条边

所以总复杂度近似为O(n^2).


七、【P3884】二叉树问题(Floyd算法)

树其实一种特殊的图。

即没有环路,一定联通,而且有且有只有一个节点没有入度的图。

  • 树上任意两点间的距离可以直接通过最短路算法获得。
  • 树的深度就是距离根节点最远的那个点的距离。
  • 树的宽度是节点最多的一层,同一层的节点距离根节点的距离都是相同的,所以也可以直接枚举获得。

AC代码:

Floyd:使用邻接矩阵存储树,先将邻接矩阵的对角线位置初始化为0(某点到自己的距离为0),其他位置初始化为INT_MAX/4(不相连的节点理论上距离为无限大,但是在计算是要考虑可能发生的溢出情况,所以除以4)

三层嵌套循环,列举每两个点 i 和 j 之间的距离,并且要考虑有中继点 k 存在的情况下,两点间的距离。(由于树是无环图,所以只需要一个中继点即可覆盖所有情况)

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <cstring>
#include <queue>using namespace std;
const int INF = 0x7fffffff / 4; //若直接为INT_MAX,则使用floyed时会发生溢出int a[105][105] = { 0 };
int b[10005] = { 0 };void init()
{for (int i = 0; i < 105; i++){for (int j = 0; j < 105; j++){if (i != j)a[i][j] = INF;}}
}int main()
{init();int n;	cin >> n;for (int i = 1; i <= n - 1; i++){int u, v;	cin >> u >> v;a[u][v] = 1;a[v][u] = 2;}for (int k = 1; k <= n; k++){for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){a[i][j] = min(a[i][j], a[i][k] + a[k][j]);}}}int maxdepth = 0;for (int i = 1; i <= n; i++){if (maxdepth < a[1][i])maxdepth = a[1][i];b[a[1][i]]++;}int maxd = 0;for (int i = 1; i <= maxdepth; i++){maxd = max(maxd, b[i]);}int u, v;cin >> u >> v;cout << maxdepth + 1 << endl;cout << maxd << endl;cout << a[u][v] << endl;
}

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

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

相关文章

【极数系列】Flink配置参数如何获取?(06)

文章目录 gitee码云地址简介概述01 配置值来自.properties文件1.通过路径读取2.通过文件流读取3.通过IO流读取 02 配置值来自命令行03 配置来自系统属性04 注册以及使用全局变量05 Flink获取参数值Demo1.项目结构2.pom.xml文件如下3.配置文件4.项目主类5.运行查看相关日志 gite…

sqli-labs第一关

1.判断是否存在注入&#xff0c;注入是字符型还是数字型? ?id1 and 11 ?id1 and 12 因为输入and 11与and 12 回显正常&#xff0c;所以该地方不是数字型。 ?id1 ?id1-- 输入单引号后报错&#xff0c;在单引号后添加--恢复正常&#xff0c;说明存在字符注入 2.猜解SQL查…

前端——JavaScript

目录 文章目录 前言 一. JavaScript基础 1.JavaScript基本结构 2. JavaScript 执行过程 3. JavaScript 引入方式 二. JavaScript 语法 1.数据类型 2.变量 2.1 var 关键字定义变量 2.2 let 关键字定义变量 2.3 var 与 let 的区别 3.字符串 3.1定义字符串 3.2 字…

Java中this引用详解

文章目录 一、 为什么要有this引用二、什么是this引用三、this引用的特性四、如何用好this关键字 一、 为什么要有this引用 我们先看一段代码 class Data {public int year;public int month;public int day;public void setDay(int y,int m,int d) {year y;month m;day d…

《动手学深度学习(PyTorch版)》笔记4.7

Chapter4 Multilayer Perceptron 4.7 Forward/Backward Propagation and Computational Graphs 本节将通过一些基本的数学和计算图&#xff0c;深入探讨反向传播的细节。首先&#xff0c;我们将重点放在带权重衰减&#xff08; L 2 L_2 L2​正则化&#xff09;的单隐藏层多层…

【教学类-44-04】20240128汉字字帖的字体(一)——文艺空心黑体

背景需求&#xff1a; 【教学类-XX -XX 】20240128名字字卡1.0&#xff08;15CM正方形手工纸、黑体&#xff0c;说明是某个孩子的第几个名字&#xff09;-CSDN博客文章浏览阅读254次&#xff0c;点赞4次&#xff0c;收藏2次。【教学类-XX -XX 】20240128名字字卡1.0&#xff0…

12.Elasticsearch应用(十二)

Elasticsearch应用&#xff08;十二&#xff09; 1.单机ES面临的问题 海量数据存储问题单点故障问题 2.ES集群如何解决上面的问题 海量数据存储解决问题&#xff1a; 将索引库从逻辑上拆分为N个分片&#xff08;Shard&#xff09;&#xff0c;存储到多个节点单点故障问题&a…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之CheckboxGroup组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之CheckboxGroup组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、CheckboxGroup组件 提供多选框组件&#xff0c;通常用于某选项的打开或关…

【python】GtkWindow程序

一、多个GtkWindow 在GTK中&#xff0c;并不推荐使用多个GtkWindow来创建多文档界面&#xff08;MDI&#xff09;&#xff0c;而是推荐使用单个GtkWindow内嵌入的小部件&#xff08;如GtkNotebook&#xff09;来实现类似的效果。然而&#xff0c;如果确实想要创建多个窗口的例…

教育能打破阶层固化吗

中式教育以应试为核心&#xff0c;强调知识的灌输和学生被动接受。随着社会的发展&#xff0c;中式教育的短板逐渐显现&#xff0c;创新能力的缺乏、对记忆的过度依赖、忽视个体差异等问题日益突出。 建议所有大学生都能去看看《上海交通大学生存手册》&#xff0c;它道出了中…

日常学习之:vue + django + docker + heroku 对后端项目 / 前后端整体项目进行部署

文章目录 使用 docker 在 heroku 上单独部署 vue 前端使用 docker 在 heroku 上单独部署 django 后端创建 heroku 项目构建 Dockerfile设置 settings.pydatabase静态文件管理安全设置applicaiton & 中间件配置 设置 requirements.txtheroku container 部署应用 前后端分别部…

(自用)learnOpenGL学习总结-高级OpenGL-模板测试

模板测试 模板测试简单来说就是一个mask&#xff0c;根据你的mask来保留或者丢弃片段。 那么可以用来显示什么功能呢&#xff1f;剪切&#xff0c;镂空、透明度等操作。 和深度缓冲的关系是&#xff1a; 先片段着色器&#xff0c;然后进入深度测试&#xff0c;最后加入模板测…

2023年中国工控自动化市场现状及竞争分析,美日占主角,国产品牌初崭头角

工控自动化是一种运用控制理论、仪器仪表理论、计算机和信息技术&#xff0c;对工业生产过程实现检测、控制、优化、调度、管理和决策&#xff0c;达到增加产量、提高质量、降低消耗、确保安全等目的综合性技术。产品应用领域广泛&#xff0c;可分为OEM型行业和项目型行业。 近…

2024年最新 MySQL的下载、安装、启动与停止

一、MySQL的下载 MySQL最常用的2个版本&#xff1a; 社区版&#xff1a;免费开源&#xff0c;自由下载&#xff0c;不提供官方技术支持&#xff0c;大多数普通用户选择这个即可。企业版&#xff1a;需要付费&#xff0c;不能在线下载&#xff0c;可以使用30天&#xff0c;提供…

aio-max-nr达到上限导致数据库性能问题

问题说明&#xff1a; rac数据库节点一表面上看由于归档等待事件导致业务性能问题。 问题分析过程&#xff1a; 查看awr报告top事件&#xff0c;等待事件主要为归档切换问题&#xff1a; 查看事件&#xff0c;归档等待达到20多分钟 检查节点alert日志发现&#xff0c;最…

Linux第37步_解决“Boot interface 6 not supported”之问题

在使用USB OTG将“自己移植的固件”烧写到eMMC中时&#xff0c;串口会输出“Boot interface 6 not supported”&#xff0c;发现很多人踩坑&#xff0c;我也一样。 见下图&#xff1a; 解决办法&#xff1a; 1、打开终端 输入“ls回车”&#xff0c;列出当前目录下所有的文件…

SpringCloud-高级篇(十六)

前面学习了Lua的语法&#xff0c;就可以在nginx去做编程&#xff0c;去实现nginx类里面的业务&#xff0c;查询Redis&#xff0c;查询tomcat等 &#xff0c;业务逻辑的编写依赖于其他组件&#xff0c;这些组件会用到OpenResty的工具去实现 &#xff08;1&#xff09;安装OpenRe…

C++(16)——vector的模拟实现

前面的文章中&#xff0c;给出了对于的模拟实现&#xff0c;本篇文章将给出关于的模拟实现。 目录 1.基本框架&#xff1a; 2. 返回值与迭代器&#xff1a; 2.1 返回值capacity与size: 2.2 两种迭代器iterator和const_iterator: 3. 扩容与push_back与pop_back&#xff1a…

后端学习:数据库MySQL学习

数据库简介 数据库&#xff1a;英文为 DataBase&#xff0c;简称DB&#xff0c;它是存储和管理数据的仓库。   接下来&#xff0c;我们来学习Mysql的数据模型&#xff0c;数据库是如何来存储和管理数据的。在介绍 Mysql的数据模型之前&#xff0c;需要先了解一个概念&#xf…

log4j2 配置入门介绍

配置 将日志请求插入到应用程序代码中需要进行大量的计划和工作。 观察表明&#xff0c;大约4%的代码专门用于日志记录。因此&#xff0c;即使是中等规模的应用程序也会在其代码中嵌入数千条日志记录语句。 考虑到它们的数量&#xff0c;必须管理这些日志语句&#xff0c;而…