数据结构与算法实验9 实现无向连通图的最小生成树

news2024/11/17 19:46:46

文章目录

  • 1.上机名称
  • 2.上机要求
  • 3.上机环境
  • 4.程序清单(写明运行结果及结果分析)
    • 4.1 程序清单
      • 4.1.1 头文件 Graph.h 内容如下:
      • 4.1.2 实现文件 Graph.cpp 内容如下:
      • 4.1.3 源文件 main.cpp 内容如下:
    • 4.2 运行结果
  • 5.上机体会

1.上机名称

实现无向连通图的最小生成树

2.上机要求

(1)编写程序实现求带权连通图最小生成树的Prim算法。
(2)编写程序实现求带权连通图最小生成树的Kruskal算法。

3.上机环境

visual studio 2022 Windows11 家庭版 64位操作系统

4.程序清单(写明运行结果及结果分析)

4.1 程序清单

4.1.1 头文件 Graph.h 内容如下:

#pragma once

#include<iostream>
#include<queue>
//按照实验要求,本次实验构建的是无向图,为后续实验方便,引进图的种类标志,尝试将有向版本、网的版本统一起来。
enum GraphKind{//枚举类型,无向图,无向网,有向图,有向网
	UN_GRAPH,UN_NET,_GRAPH,_NET
};

typedef char Data;	//图的顶点里的数据元素
typedef int flag;	    //用于标注是否被遍历

typedef struct NeighbourNode {//邻接表的一个成员
	int id;			//邻接表里的下标
	int weight;		//权重,默认为0
}NBnode, * pNBnode;

typedef struct GNode {//定义图的顶点元素结构
	Data data;				//数据成员
	pNBnode* LNeighbours;	//左邻(入)接表
	pNBnode* RNeighbours;   //右邻(出)接表
	flag is_visited;		       //标注是否被遍历
	flag fatherid;			   //标注上一级节点id,用于Kruskal算法辅助
	int LN_cnt;			   //左邻数
	int RN_cnt;			   //右邻数
}Gnode, * pGnode;

typedef struct ARC {//一个弧的抽象数据类型
	pGnode left;	//起点
	int leftid;		
	pGnode right;	//终点
	int rightid;
	int weight;
}Arc, * pArc;

class Graph {
public:
	//创建一个顶点数为vex_num的图,图的类型为Kind
	Graph(int vex_num = 0, int Kind = 0);
	//通过邻接矩阵创建图	
	Graph(int** array_for_summon, int size, int Kind);
	~Graph();								//析构函数
	void insert(Data data);					//插入顶点
	void setdata(int id, Data data);		    //设置顶点数据
	void link(int id1,int id2,int weight = 1);	    //使两个顶点之间产生边关联,weight == 0 表示无关联。
	void CreateArray();						//通过传入的邻接矩阵生成图,并对矩阵的合法性进行检测
	void printNBS(int id);					//打印id顶点的邻接表
	void printARR();						//打印图的邻接矩阵
	void printArc();						//打印所有边
	void DFS(int firstid = 0);				//从下标为firstid的顶点深度优先遍历
	void BFS(int firstid = 0);				//从下标为firstid的顶点广度优先遍历
	void MSTPrim(int firstid = 0);			//使用Prim算法求最小生成树
	void MSTKruskal(int firstid = 0);		    //使用kruskal算法求最小生成树
	void MergeArcWeigt(int low ,int high);    //对带权边进行从小到大的排序,参数为0,arc_num
	const int get_vex_num();				//返回顶点数
	const int get_arc_num();					//返回边数,无向图、网返回值是边的两倍,在函数调用过程中自洽
protected:
	void makeneighbour(int id1, int id2, int weight = 1);//造邻居
	void SetFlag();					//初始化两个flag
	void DFSearch(int firstid = 0);		//对一个顶点的DFS
	void BFSearch(int firstid = 0);        //对一个顶点的DFS
	void swap(int id1, int id2);			//在排序中对两个边进行互换
	int fa(int id);						//返回代表元素,用于kruskal算法
	int vex_num;			//顶点数量
	int arc_num;			//弧数量
	int** GArray;			//邻接矩阵
	int GKind;			//图的类型标记
	pGnode* vex;			//存放顶点的顺序表
	pArc* arc;			//存放弧的顺序表
};

4.1.2 实现文件 Graph.cpp 内容如下:

#include "Graph.h"
Graph::Graph(int vex_num , int Kind ){
	this->vex_num = vex_num;
	vex = new pGnode[vex_num];
	for (int i = 0; i < vex_num; i++) {
		vex[i] = new Gnode;
	}
	for (int i = 0; i < vex_num; i++) {
		vex[i]->LN_cnt = 0;
		vex[i]->RN_cnt = 0;
		vex[i]->LNeighbours = new pNBnode;
		vex[i]->RNeighbours = new pNBnode;
		vex[i]->is_visited = 0;
	}
	GArray = new int* [vex_num]; for (int i = 0; i < vex_num; i++)GArray[i] = new int[vex_num];
	for (int i = 0; i < vex_num; i++)for (int j = 0; j < vex_num; j++) GArray[i][j] = 0;
	GKind = Kind;
	arc_num = 0;
	arc = new pArc;
}

Graph::Graph(int** array_for_summon, int size, int Kind){   
	vex_num = size;
	arc_num = 0;
	vex = new pGnode[vex_num];
	for (int i = 0; i < vex_num; i++) {
		vex[i] = new Gnode;
	}
	for (int i = 0; i < vex_num; i++) {
		vex[i]->LN_cnt = 0;
		vex[i]->RN_cnt = 0;
		vex[i]->LNeighbours = new pNBnode;
		vex[i]->RNeighbours = new pNBnode;
		vex[i]->is_visited = 0;
	}
	GKind = Kind;
	GArray = new int*[size];for (int i = 0; i < size; i++) GArray[i] = new int[size];
	for (int i = 0; i < size; i++) for (int j = 0; j < size; j++) GArray[i][j] = array_for_summon[i][j];
	CreateArray();
}

Graph::~Graph(){
	for (int i = 0; i < vex_num; i++) delete[]GArray[i];
	delete[]GArray;
	for (int i = 0; i < vex_num; i++) {
		delete[]vex[i]->LNeighbours;
		delete[]vex[i]->RNeighbours;
		vex[i]->LN_cnt = 0;
		vex[i]->RN_cnt = 0;
		vex[i]->is_visited = 0;
		vex[i]->data = 0;
	}
	delete[]vex;
	vex_num = 0;
	std::cout << "内存释放完毕!" << std::endl;
}

void Graph::insert(Data data){
	++vex_num;
	int** tmp = new int* [vex_num]; for (int i = 0; i < vex_num; i++) tmp[i] = new int[vex_num];
	for (int i = 0; i < vex_num; i++) for (int j = 0; j < vex_num; j++) {
		if (i == vex_num - 1 || j == vex_num - 1) tmp[i][j] = 0;
		else tmp[i][j] = GArray[i][j];
	}
	if (vex_num != 1) {	//不要释放空
		for (int i = 0; i < vex_num - 1; i++)delete[] GArray[i];
		delete []GArray;
	}
	vex[vex_num - 1]->data = data;
	std::cout << "new vertex ID: " << vex_num - 1 << "(start from zero)" << std::endl;
	GArray = tmp;
}

void Graph::setdata(int id, Data data){
	vex[id]->data = data;
}

void Graph::link(int id1, int id2, int weight ){
	switch (GKind){
	case UN_GRAPH: {//无向图
		if (id1 == id2) makeneighbour(id1, id2);
		else{
			makeneighbour(id1, id2);
			makeneighbour(id2, id1);
		}
		break;
	}
	case UN_NET: {//无向网
		if(id1==id2) makeneighbour(id1, id2, weight);
		else {
			makeneighbour(id1, id2, weight);
			makeneighbour(id2, id1, weight);
		}
		break;
	}
	case _GRAPH: {//有向图
		makeneighbour(id1, id2);
		break;
	}
	case _NET: {//有向网
		makeneighbour(id1, id2, weight);
		break;
	}
	default:std::cout << "Link failed!" << std::endl; break;
	}
}

void Graph::CreateArray(){
	switch (GKind)
	{
	case UN_GRAPH:
	case UN_NET: {
		for (int i = 0; i < vex_num; i++) {
			for (int j = 0; j <= i; j++) {
				if (GArray[i][j] != GArray[j][i]) {
					std::cout << "传入的矩阵作为无向图/网不合法!输入Y/N选择兼容或退出:" << std::endl;
					char c = getchar(); getchar();
					switch (c) {
					default:exit(-1);
					case 'y':case 'Y': {
						link(i, j, GArray[i][j] > GArray[j][i] ? GArray[i][j] : GArray[j][i]);
						continue;
					}
					}
				}
				if (GArray[i][j] != 0 ) link(i, j, GArray[i][j]);
			}
		}
		break;
	}
	case _GRAPH:
	case _NET: {
		for (int i = 0; i < vex_num; i++) {
			for (int j = 0; j < vex_num; j++) {
				if (GArray[i][j] != 0)link(i, j, GArray[i][j]);
			}
		}
		break;
	}
	default: std::cout << "Summon From Array Failed!" << std::endl;
	}
}

void Graph::makeneighbour(int id1, int id2, int weight ) {
	//id1 出度+1。
	pNBnode* fresh = new pNBnode[vex[id1]->RN_cnt + 1];
	for (int i = 0; i < vex[id1]->RN_cnt + 1; i++) fresh[i] = new NBnode;
	for (int i = 0; i < vex[id1]->RN_cnt; i++) {
		fresh[i]->id = vex[id1]->RNeighbours[i]->id;
		fresh[i]->weight = vex[id1]->RNeighbours[i]->weight;
	}
	fresh[vex[id1]->RN_cnt]->id = id2;
	fresh[vex[id1]->RN_cnt]->weight = weight;
	for (int i = 0; i < vex[id1]->RN_cnt; i++) delete[] vex[id1]->RNeighbours[i];
	delete[] vex[id1]->RNeighbours;
	vex[id1]->RNeighbours = fresh;
	
	//id2 入度+1。
	pNBnode* fresh2 = new pNBnode[vex[id2]->LN_cnt + 1];
	for (int i = 0; i < vex[id2]->LN_cnt + 1; i++) fresh2[i] = new NBnode;
	for (int i = 0; i < vex[id2]->LN_cnt; i++) {
		fresh2[i]->id = vex[id2]->LNeighbours[i]->id;
		fresh2[i]->weight = vex[id2]->LNeighbours[i]->weight;
	}
	fresh2[vex[id2]->LN_cnt]->id = id1;
	fresh2[vex[id2]->LN_cnt]->weight = weight;
	for (int i = 0; i < vex[id2]->LN_cnt; i++) delete[] vex[id2]->LNeighbours[i];
	delete[] vex[id2]->LNeighbours;
	vex[id2]->LNeighbours = fresh2;
	
	//弧段添加
	pArc* fresh3 = new pArc[arc_num + 1];
	for (int i = 0; i < arc_num + 1; i++) {
		fresh3[i] = new Arc;
		fresh3[i]->right = new Gnode;
		fresh3[i]->left = new Gnode;
	}
	for (int i = 0; i < arc_num; i++) fresh3[i] = arc[i];
	fresh3[arc_num]->left = vex[id1];
	fresh3[arc_num]->right = vex[id2];
	fresh3[arc_num]->weight = weight;
	fresh3[arc_num]->leftid = id1;
	fresh3[arc_num]->rightid = id2;
	delete[] arc;
	arc = fresh3;

	//别忘了对邻接矩阵和用于记录的数据进行修改
	GArray[id1][id2] = weight;
	vex[id1]->RN_cnt++;
	vex[id2]->LN_cnt++;
	arc_num++;
}

void Graph::printNBS(int id){
	pGnode obj = vex[id];
	switch (GKind)
	{
	case UN_GRAPH: {
		std::cout << "顶点ID:" << id << "的邻居ID:" << std::endl;
		if (obj->RN_cnt != 0)
			for (int i = 0; i < obj->RN_cnt; i++)
				std::cout << obj->RNeighbours[i]->id << " ";
		std::cout << std::endl;
		break;
	}
	case UN_NET: {
		if (obj->LN_cnt != 0)
			std::cout << "顶点ID:" << id << "的邻居ID[权重]:" << std::endl;
		for (int i = 0; i < obj->LN_cnt; i++)
			std::cout << obj->LNeighbours[i]->id << "[" << obj->LNeighbours[i]->weight << "]" << " ";
		std::cout << std::endl;
		break;
	}
	case _GRAPH: {
		std::cout << "顶点ID:" << id << std::endl;
		if (obj->LN_cnt != 0) {
			std::cout << "左邻ID:" << std::endl;
			for (int i = 0; i < obj->LN_cnt; i++)
				std::cout << obj->LNeighbours[i]->id << " ";
			std::cout << std::endl;
		}
		if (obj->RN_cnt != 0) {
			std::cout<< "\n右邻ID:" << std::endl;
			for (int i = 0; i < obj->RN_cnt; i++)
				std::cout << obj->RNeighbours[i]->id << " ";
			std::cout << std::endl;
		}
		break;
	}
	case _NET: {
		std::cout << "顶点ID:" << id << std::endl;
		if (obj->LN_cnt != 0) {
			std::cout << "左邻ID[权重]:" << std::endl;
			for (int i = 0; i < obj->LN_cnt; i++)
				std::cout << obj->LNeighbours[i]->id <<
				"[" << obj->LNeighbours[i]->weight << "]" << " ";
			std::cout << std::endl;
		}
		if (obj->RN_cnt != 0) {
			std::cout << "右邻ID[权重]:" << std::endl;
			for (int i = 0; i < obj->RN_cnt; i++)
				std::cout << obj->RNeighbours[i]->id <<
				"[" << obj->RNeighbours[i]->weight << "]" << " ";
			std::cout << std::endl;
		}
		break;
	}
	default:
		std::cout << "Find Neighbours Error!" << std::endl;
	}
}

void Graph::printARR(){
	std::cout << "图的邻接矩阵:\n";
	for (int i = 0; i < vex_num; i++){
		for (int j = 0; j < vex_num; j++) {
			std::cout << GArray[i][j] << " ";
		}
		std::cout << std::endl;
	}
}
void Graph::printArc(){
	switch (GKind) {
	case UN_GRAPH:
	case UN_NET: {
		for (int i = 0; i < arc_num; i+=2) {
			std::cout << "(" << arc[i]->left->data << " " << arc[i]->weight << " " << arc[i]->right->data << ")" << std::endl;
		}
		break;
	}
	case _GRAPH:
	case _NET: {
		for (int i = 0; i < arc_num; i ++) {
			std::cout << "<" << arc[i]->left->data << " " << arc[i]->weight << " " << arc[i]->right->data << ">" << std::endl;
		}
		break;
	}
	default:std::cout << "遍历边序列有误" << std::endl;
	}
	
}

void Graph::DFS(int firstid){
	SetFlag();
	DFSearch(firstid);
	for (int i = 0; i < vex_num; i++) {
		if (vex[i]->is_visited == 0)DFSearch(i);
	}
	std::cout << std::endl;

}

void Graph::BFS(int firstid){	
	SetFlag();
	BFSearch(firstid); 
	for (int i = 0; i < vex_num; i++) {
		if (vex[i]->is_visited == 0)BFSearch(i);
	}
	std::cout << std::endl;
}

void Graph::MSTPrim(int firstid){
	SetFlag();
	std::queue<int> v;
	v.push(firstid);
	vex[firstid]->is_visited = 1;
	while (v.size() != vex_num) {
		int wflag = 65535;
		int idflag = 65535;
		int iflag = firstid;
		for (int i = 0; i < v.size(); i++) {
			for (int j = 0; j < vex[i]->RN_cnt; j++) {
				if (vex[vex[i]->RNeighbours[j]->id]->is_visited == 0
					&& wflag > vex[i]->RNeighbours[j]->weight) {
					wflag = vex[i]->RNeighbours[j]->weight;
					idflag = vex[i]->RNeighbours[j]->id;
					iflag = i;
				}
			}
		}
		std::cout << vex[iflag]->data << " " << wflag << " " << vex[idflag]->data << std::endl;
		v.push(idflag);
		vex[idflag]->is_visited = 1;
	}
		
}

void Graph::MSTKruskal(int firstid){
	SetFlag();
	MergeArcWeigt(0,arc_num);			//首先我们进行排序为贪心算法做准备
	int num = 0;
	for (int i = 0; i <arc_num; i++){
		if (num == vex_num - 1)break;	//达到要求就退出
		else {
			if (fa(arc[i]->leftid) != fa(arc[i]->rightid)) {	//如果一个边左右不属于一个代表元素,也就是说他们不在一个连通图中,将他们连到一起。
				arc[i]->right->fatherid = arc[i]->leftid;
				num++;
				std::cout << arc[i]->left->data << " " << arc[i]->weight << " " << arc[i]->right->data << std::endl;
			}
			else if (fa(arc[i]->leftid) != fa(arc[i]->rightid))continue;
		}
	}
	if (num != vex_num - 1) {	//可能出现不连通的情况,这时有这个式子进行判断进行提示
		std::cout << "所给图并非连通图!" << std::endl;
		exit(-2);
	}
}

void Graph::MergeArcWeigt(int low,int high){//此部分代码参考快速排序
		int flag = low;	//标杆元素下标
		if (low == high) return;
		for (int i = flag + 1; i < high; i++) {
			if (arc[flag]->weight <= arc[i]->weight)continue;
			if (arc[flag]->weight > arc[i]->weight) {
				swap(flag + 1, i);
				swap(flag, flag + 1);
				flag++;
			}
		}
		if (flag > low)	MergeArcWeigt(low, flag - 1);
		if (flag < high)MergeArcWeigt(flag + 1, high);
}

const int Graph::get_vex_num(){
	return vex_num;
}

const int Graph::get_arc_num(){
	return arc_num;
}

void Graph::SetFlag(){
	for (int i = 0; i < vex_num; i++) {
		vex[i]->is_visited = 0;
		vex[i]->fatherid = i;
	}
}

void Graph::DFSearch(int firstid){
	if (vex[firstid]->is_visited == 0) {	//如果元素没被访问
		vex[firstid]->is_visited = 1;		//进行访问
		std::cout << vex[firstid]->data << " ";
		for (int i = 0; i < vex[firstid]->RN_cnt; i++) {//对这个元素所有右邻
			if (vex[vex[firstid]->RNeighbours[i]->id]->is_visited == 0) {	//如果没被访问
				DFSearch(vex[firstid]->RNeighbours[i]->id);					//进行访问
			}
		}
	}
	
}

void Graph::BFSearch(int firstid){
	std::queue<int> q;		//一个队列
	q.push(firstid);		//放入一个元素
	vex[firstid]->is_visited = 1;	//标记为访问过
	while (!q.empty()) {	//当队列非空的时候
		for (int i = 0; i < vex[q.front()]->RN_cnt; i++) {		//对队头元素所有的右邻
			int nextid = vex[q.front()]->RNeighbours[i]->id;	//拿到右邻的id
			if (vex[nextid]->is_visited == 0) {					//如果没有被访问
				q.push(nextid);									//入队,标记为访问过
				vex[nextid]->is_visited = 1;
			}									
			else continue;
		}
		std::cout << vex[q.front()]->data << " ";
		q.pop();	//删除队头元素
	}
	
}

void Graph::swap(int id1, int id2){//用于快速排序中改变指针指向
	pArc tmp = arc[id1];
	arc[id1] = arc[id2];
	arc[id2] = tmp;
}

int Graph::fa(int id){
	if (vex[id]->fatherid == id) return id;
	else {
		return fa(vex[id]->fatherid);
	}
}

4.1.3 源文件 main.cpp 内容如下:

#include"Graph.h"
int main() {
	int** arr_for_summon = new int* [8]; for (int i = 0; i < 8; i++)arr_for_summon[i] = new int[8];
	int arr[8][8] = {
		0, 1, 0, 2, 0, 3, 0, 4,
		1, 0, 4, 0, 5, 6, 0, 0,
		0, 4, 0, 3, 0, 0, 0, 0,
		2, 0, 3, 0, 2, 0, 0, 5,
		0, 5, 0, 2, 0, 1, 0, 0,
		3, 6, 0, 0, 1, 0, 1, 0,
		0, 0, 0, 0, 0, 1, 0, 2,
		4, 0, 0, 5, 0, 0, 2, 0 };
	for (int i = 0; i < 8; i++)for (int j = 0; j < 8; j++)arr_for_summon[i][j] = arr[i][j];
	Graph gr1(arr_for_summon, 8, UN_NET);

	for (int i = 0; i < 8; i++) {
		gr1.setdata(i, 'A' + i);
	}
	for (int i = 0; i < 8; i++) {
		gr1.printNBS(i);
	}
	//gr1.printARR();
	std::cout << "深度优先遍历" << std::endl;
	gr1.DFS();
	std::cout << "广度优先遍历" << std::endl;
	gr1.BFS();
	std::cout << "Prim算法最小生成树:" << std::endl;
	gr1.MSTPrim();
	std::cout << "Kruskal算法最小生成树:" << std::endl;
	gr1.MSTKruskal();
}

4.2 运行结果

在这里插入图片描述
在这里插入图片描述

5.上机体会

本次实验在上次实验基础上,利用矩阵输入,在无向连同图中完成了Prim算法和Kruskal算法,进行最小生成树的生成。在实验过程中发现了上次实验中存在的问题缺陷,例如在某些循环里将‘i’写成了‘1’,导致访问越界问题,可见在一个项目完成的过程中需要进行全面的测评。在本次实验中主要掌握了两种算法思想:一个是“做标记”,即在不确定是否满足条件的情况下,用一个flag先标记数据,在满足条件下更改flag以减少在循环里处理的次数,对于在一个数据群里需要按照某个规律找到有限个满足条件的数据时十分实用;另一个是“代表元素”,也就是简单的并查集,在大量数据群体中,若要拎出两个元素对它们是否在一个群体中进行判断,可以用到这样的思想:每个群体都派出一个代表元素,只要每个在群体里的数据知道自己的代表元素是谁就行,那样任意两个元素是否在一个群体里,只要看他们的代表元素是否相同就行,相比于无脑的循环查找判断能够大大降低时间复杂度。

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

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

相关文章

整数在内存中的存储(c语言)

1.原码 反码 补码&#xff08;以及他们之间的转换&#xff09; 当一个数为正数的时候&#xff0c;不存在原码反码补码的差别&#xff0c;也就是一样的&#xff1b; 当一个数为负数的时候&#xff0c;以-1为例子&#xff0c;对这个过程进行讲解。 1000 0000 0000 0000 0000 0…

多路复用IO

一。进程处理多路IO请求 在没有多路复用IO之前&#xff0c;对于多路IO请求&#xff0c;一般只有阻塞与非阻塞IO两种方式 1.1 阻塞IO 需要结合多进程/多线程&#xff0c;每个进程/线程处理一路IO 缺点&#xff1a;客户端越多&#xff0c;需要创建的进程/线程越多&#xff0c…

python 图片加文字 文字自动上下左右居中 自动换行居中对齐

一.实现效果展示 二.代码 # -*- coding: utf-8 -*- # Time : 2024/9/26 17:22 # Author : Cocktail_pyfrom PIL import Image, ImageFont, ImageDrawdef split_string(s, num_parts):length len(s)chunk_size length // num_partsremainder length % num_partsparts […

数智化引领传媒新变革,又一场技术的盛宴!

文 | 智能相对论 作者 | 陈泊丞 2024巴黎奥运会在塞纳河畔为世界呈现了一场精彩绝伦的体坛盛宴。回顾今年的直播&#xff0c;每一个观众或许都可以在屏幕前感受到更胜往届的体育表现力和竞赛节目效果。 在超高清制播技术支持下&#xff0c;不仅制播画质变高清了&#xff0c;…

ASO关键词研究-9个步骤帮您找到应用商店优化的完美关键词

应用商店优化是一种让您的应用展示给更多用户的有效方法。为此&#xff0c;您需要在应用元数据中使用正确的关键字&#xff0c;以帮助 Apple 和 Google 的搜索算法知道何时在搜索结果中显示您的应用。如果您做得正确&#xff0c;他们会向更多人展示您的应用&#xff0c;而更多的…

python全栈学习项目案例(一)atm+购物车

atm购物车 文章目录 atm购物车一、项目需求二、项目构架图三、视图的实现四、登录认证五、转账功能六、购物功能 一、项目需求 二、项目构架图 其中用户功能层中有呈现给用户的视图、各个功能的简单函数(这些简单函数需要调用接口层中函数的具体功能) 接口层存放各个功能的具体…

自动化测试数据管理问题

在自动化测试中&#xff0c;关于数据管理的更好实践确实存在&#xff0c;这些实践可以帮助提高测试的效率和质量。以下是一些推荐的最佳实践&#xff1a;1. 使用Test Data Builder模式&#xff1a;这种模式可以帮助隐藏测试数据准备的细节&#xff0c;在测试代码中只显示地对测…

每日OJ题_牛客_NC1大数加法_高精度加法

目录 牛客_NC1大数加法_高精度加法 题目解析 C代码 Java代码 牛客_NC1大数加法_高精度加法 题目解析 模版类型的算法题&#xff0c;模拟加法列竖式运算的过程即可。 假定算法流程&#xff1a; 设定 i&#xff0c;j 两指针分别指向 s&#xff0c;t 尾部&#xff0c;模拟…

2024网络安全面试指南(非常详细)收藏这一篇就够了

1.1 网络安全行业现状 安全行业起步晚。安全行业整体起来才没几年&#xff0c;多数企业因为资源投入和建设时间原因导致覆盖面和深入度都不够&#xff0c;这其中甚至包括一些国内大厂&#xff0c;并没有想象的那么安全。其安全水位仅能应付一些白帽子级别&#xff0c;针对专业…

记录一次学习--委派攻击学习

目录 为什么要使用委派 什么账号可以使用委派 非约束性委派 这里有一张图 利用 流程 约束性委派 这里有一张图 如何利用 条件 具体流程 为什么要使用委派 这个是因为可能A服务需要B服务的支持&#xff0c;但是A服务的权限不可以使用B服务。然后这时就可以让域用户将…

2024年【烟花爆竹经营单位主要负责人】免费试题及烟花爆竹经营单位主要负责人考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 烟花爆竹经营单位主要负责人免费试题是安全生产模拟考试一点通总题库中生成的一套烟花爆竹经营单位主要负责人考试技巧&#xff0c;安全生产模拟考试一点通上烟花爆竹经营单位主要负责人作业手机同步练习。2024年【烟…

吉林大学微机接口实验五:D/A转换

1.实验内容 2.实验原理/预备知识 D/A转换器TLC7528是关键&#xff0c;其用法参见&#xff1a; 芯片部件汇总&#xff1a;常用功能部件大全-CSDN博客 直接找"TLC7528 D/A数模转换器"&#xff08;实际上学校的讲义已经讲的很清楚&#xff0c;我只是给搬到了博客里&…

C++ | Leetcode C++题解之第430题扁平化多级双向链表

题目&#xff1a; 题解&#xff1a; class Solution { public:Node* flatten(Node* head) {function<Node*(Node*)> dfs [&](Node* node) {Node* cur node;// 记录链表的最后一个节点Node* last nullptr;while (cur) {Node* next cur->next;// 如果有子节点…

【源码+文档+调试讲解】重庆旅游景点数据分析系统python

摘 要 重庆旅游景点数据分析系统是一个专门为旅游管理部门和景点运营商设计的信息化工具&#xff0c;它通过集成和分析各种数据来优化景点管理和提升游客体验。该系统能够实时收集游客流量、景点信息、满意度反馈等关键信息&#xff0c;帮助管理者洞察游客行为和市场趋势。系统…

C++ const成员函数

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 C const引用常量 使用规则 引用常量对象&#xff1a;可以引用一个常量对象&#xff0…

Unity 的Event的Use()方法

对于Event的Use方法&#xff0c;其在调用后将不会再判断同类型的事件 这种情况下&#xff0c;第二个MosueDown不会进入&#xff0c;因为已经Use 如果把Use注释掉 依旧能进入第二个MosueDown 也就是说当使用了Use方法&#xff0c;相同的事件类型不会进第二遍

【文心智能体】从零到一的优质智能体构建全攻略

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 创作平台&#xff1a;文心智能体平台&#xff1a; 基本配置智能体名称与简介人物设定回复逻辑prompt提示词的编写开场白设定与开场白…

利士策分享,领导者素养自检:五维审视法

利士策分享&#xff0c;领导者素养自检&#xff1a;五维审视法 在人生的广阔舞台上&#xff0c;每个人都蕴藏着成为领导者的潜力&#xff0c;但如何知晓自己是否已具备那份独特的素养&#xff1f; 这需要我们进行一次深刻而诚实的自我审视。 以下五个维度&#xff0c;或许能为你…

K8s Calico替换为Cilium,以及安装Cilium过程(鲁莽版)

迁移CNI插件的3种办法&#xff1a; 1、创建一个新的集群&#xff0c;通过Gitops的方式迁移负载&#xff0c;然而&#xff0c;这可能涉及大量的准备工作和潜在的中断。 2、另一种方法是重新配置/etc/cni/net.d/指向Cilium。但是&#xff0c;现有的pod仍将由旧的…