【数据结构与算法(C语言)】离散事件模拟- 单链表和队列的混合实际应用

news2024/11/27 8:48:46

目录

  • 1. 前言
  • 2. 流程图
  • 3. 数据结构
    • 3.1 单链表
    • 3.2 链式队列
  • 4. 核心函数
    • 4.1 银行业务模拟 void BankSimulation()
    • 4.2 初始化 void OpenForDay()
    • 4.3 客户到达 void CustomerArrived(Event en)
    • 4.4 客户离开 void CustomerArrived(Event en)
  • 5. 非核心函数
    • 5.1 新建客户 NewCustomer
    • 5.2 新建事件 NewEvent
    • 5.3 查找最短的队列 ShortestQueueIndex
    • 5.4 打印队列信息 PrintQueues
    • 5.5 销毁数据结构 DestoryDataStruct
    • 5.6 休眠函数 sleep
  • 6. 编码全过程
    • 6.1 数据结构头文件
    • 6.2 队列函数文件
    • 6.3 有序链表函数文件
    • 6.4 新建主程序文件
  • 7. 运行结果
  • 8. 小结

1. 前言

  假设银行有4个窗口对外接待客户,从早晨银行开门不断有客户进入银行。每个客户总是排队到人员最少的窗口办理业务。现在需要编写一个程序以模拟银行的这种业务并计算一天中银行逗留的平均时间。
  为了计算这个平均时间,只需要将每个客户的离开银行时间减去到达银行时间得到一个客户的逗留事件,将所有客户的时间总和除以客户数就是所有的平均时间。称客户到达银行和离开银行这两个时刻发生的事情为事件,则整个模拟程序将按事件发生的先后顺序进行处理,这样一种模拟程序称作事件驱动模拟

2. 流程图

在这里插入图片描述

3. 数据结构

  需要两种数据结构:有序单链表和链式队列。

3.1 单链表

  单链表用于存放事件,事件分类为两类:一类客户到达事件;另一类客户离开事件。事件按照发生时刻按照顺序存放在单链表中。

3.2 链式队列

  4个队列分别模拟4个窗口,用于存放排队的客户。客户信息主要包括客户的编号、客户到达的时候、客户办理业务的时间。因为客户的人数不确定,所以使用链式存储方式。

4. 核心函数

  为了让程序更加清晰,本文不详细介绍队列和单链表的实现,具体实现详解可查看以往的博客《线性表-单链表》和《队列-链队列》,本博文直接展示如何使用这些数据结构。
  核心函数只有4个:银行业务模拟总函数 void BankSimulation()、银行开始营业(初始化) void OpenForDay()、客户达到函数 void CustomerArrived(Event en) 、客户离开函数void CustomerDeparture(Event en)

4.1 银行业务模拟 void BankSimulation()

功能:银行业务的总体运行,其他所有函数都包含在此函数中。
   主要包含一个循环,每次从事件链表中提取一个事件,并根据事件类型来驱动具体的流程。这个流程包括客户达(入列),客户离开(出列)。
实现

void BankSimulation(){
	Event e;
	srand((unsigned)time(NULL));//使用时间生成一个随机种子
	OpenForDay();
	while(!ListEmpty(eventList))
	{
		ListDelFstNode(&eventList, &e); //从链表中提取一个事件
		if(e.nType==0)								//事件类型0,即客户到达
			CustomerArrived(e);				  //客户到达
		else 
			CustomerDeparture(e);			  //客户离开

		/*下面几行就是打印当前链表和队列*/
		printf("\n事件链表: ");
		ListTraverse(eventList);
		printf("\n\n");
		PrintQueues();
		printf("\n\n");

	}
	printf("每个客户平均时间:%f",(float)TotalTime/CustomerNumber);
	DestoryDataStruct();//最后销毁链表和数据结构,释放内存空间
}

4.2 初始化 void OpenForDay()

功能:银行开门,即初始化函数。
   初始化事件链表、4个队列,同时生成第一个客户的到达事件,插入到事件链表中。
实现

void OpenForDay()
{
	int i;
	InitList(&eventList);
	ListInsertByOrder(&eventList, NewEvent(0,0));
	for(i=0;i<4;i++)
		InitQueue(&queue[i]);
}

4.3 客户到达 void CustomerArrived(Event en)

功能:客户到达,主要功能有以下三个。
    a). 生成一个新的客户到达事件,插入到事件链表中;
    b). 将事件en中的刚到达客户信息插入到最短的队列中;
    c). 如果队列 插入前是空队列,则生成一个离开事件插入到事件链表中(空队列,说明客户到队列中,业务就立马办理了,无需等待)。
实现

/*	事件en到达,主要有以下功能
	1. 生成一个新的客户到达事件,插入到事件链表中
	2. 将事件en中的刚到达客户信息插入到最短的队列中;
	3. 如果队列 插入前是空队列,则生成一个离开事件插入到事件链表中(空队列,说明客户到队列中,业务就立马办理了,无需等待)
*/
void CustomerArrived(Event en)
{	
	int i,duration;	//duration当前到达事件中的客户办理业务的持续时间
	int interTime_newCustomer;   // 新生成客户达到的间隔时间;
	int arrivalTime_newCustomer; //新生成客户的到达事件
	interTime_newCustomer = rand()%5 + 1;//新生成客户到达时间设置5分钟之内
	duration = rand()%30 + 1;			 //当前到达客户业务办理时间在30分钟
	arrivalTime_newCustomer = en.occurTime+interTime_newCustomer ;
	printf("时刻 %d: %d号 客户到达;\n",en.occurTime,++CustomerNumber);
	if(arrivalTime_newCustomer < CloseTime)
	ListInsertByOrder(&eventList,NewEvent(arrivalTime_newCustomer,0)); //生成一个新的客户到达事件插入到事件链表中

	i=ShortestQueueIndex();
	EnQueue(&queue[i],NewCustomer(CustomerNumber,en.occurTime,duration)); //到达客户入列
	if(QueueLength(queue[i])==1)//插入之前是空队列
		ListInsertByOrder(&eventList,NewEvent(en.occurTime+duration,i+1));//生成一个离开事件插入到事件链表中
}

4.4 客户离开 void CustomerArrived(Event en)

功能:客户到达,主要功能有以下两个。
    a).从队列中删除客户,打印离开信息,统计总用时;
    b). 如果队列不空,则获取队列(删除客户)的下一个客户,以表示下一个客户开始办理业务,并将这个客户的离开事件插入到事件链表中去。
实现

// 顾客离开事件
// 功能1 :从队列中删除客户,打印离开信息,统计总用时; 
// 功能2 :如果队列不空,则获取队列(删除客户)的下一个客户,
//		   以表示下一个客户开始办理业务,并将这个客户的离开事件插入到LinkList中去。
void CustomerDeparture(Event en)
{
	int i=en.nType-1;
	QElemType customer;
	DeQueue(&queue[i],&customer);
	printf("时刻 %d: %d号 客户离开;\n",en.occurTime,customer.number);
	TotalTime += en.occurTime - customer.arrivalTime;
	if(!QueueEmpty(queue[i])){
		GetHead(queue[i],&customer); //从队列中获取下一个客户
		ListInsertByOrder(&eventList,NewEvent(en.occurTime+customer.duration,i+1));//下个客户的离开事件插入事件链表
	}
}

5. 非核心函数

除了上面4个核心函数,还有几个非核心函数。很简单,无需花时间去理解。如生成新的事件、生成新的客户、获取长达字段的队列等等

5.1 新建客户 NewCustomer

功能:新建一个客户信息的元素(队列的元素)
实现

/*新建一个客户信息的元素(队列的元素)*/
QElemType NewCustomer(int number, int arrivalTime,int duration)
{
	QElemType e;
	e.number=number;
	e.arrivalTime=arrivalTime;
	e.duration=duration;
	return e;
}

5.2 新建事件 NewEvent

功能:新建一个事件(单链表结点中的数据)
实现

/*新建一个事件(单链表结点中的数据)*/
ElemType NewEvent(int occurTime,int nType)
{
	Event e;
	e.occurTime=occurTime;
	e.nType=nType;
	return e;
}

5.3 查找最短的队列 ShortestQueueIndex

功能:查找长度最短的队列
实现

/*在队列数组中查找长度最短的队列,并返回其下标*/
int ShortestQueueIndex()
{
	int i,minQueueIndex=0;			 //minQueueIndex 最短队列下标
	int minLen=QueueLength(queue[0]);//定义一个最小长度变量
	for(i=1;i<4;i++)
	{
		if(minLen>QueueLength(queue[i])){
			minLen=QueueLength(queue[i]);
			minQueueIndex=i;
		}
	}
	return minQueueIndex;
}

5.4 打印队列信息 PrintQueues

功能:打印4个队列的信息
实现

/*打印4个队列*/
void PrintQueues()
{
	int i=0;
	for(;i<4;i++)
	{
		printf("%d 号窗口:",i+1);
		QueueTraverse(queue[i]);
	}
}

5.5 销毁数据结构 DestoryDataStruct

功能:销毁数据结构,程序运行完毕,务必销毁数据结构,释放手动申请的内存空间
实现

/*销毁链表和队列*/
void DestoryDataStruct()
{
	int i=0;
	DestroyList(&eventList);
	for(;i<4;i++)
	{
		DestroyQueue(&queue[i]);
	}
}

5.6 休眠函数 sleep

功能:程序休眠(暂停)一段时间。这个函数不是必要的。本示例在循环中加上,纯粹是为了更加清楚的在控制台观察程序运行过程
实现

//休眠函数
void sleep(float time)
{
   clock_t   now   =   clock(); 
   while( clock() - now < time*1000); 
}

6. 编码全过程

为了项目的清晰,将单链表和队列的实现方法单独存放两个文件中。

6.1 数据结构头文件

  首先新建一个数据结构的头文件 DataStruct.h,其中包含有序单链表和队列的元素、结点、结构定义。

/*队列*/
#define TRUE  1
#define FALSE 0
#define OK    1
#define ERROR 0

typedef  int Status;

/* 以下是队列Queue的结构和基本操作 的声明*/
typedef struct {
	 int number;	   //编号,标识客户
	 int arrivalTime;  //客户到达时间
	 int duration;	   //办理事务时间
} QElemType;		   //队列的元素类型

typedef struct QNode{
	QElemType data;	   
	struct QNode * next;
} QNode;			   //队列的结点类型

typedef struct {
	QNode * front;	   //队头指针
	QNode * rear;	   //队尾指针
	int length;		   //队列长度
}LinkQueue;			   //定义一个链式队列

Status InitQueue(LinkQueue * queue);			/*初始化队列,申请一个头结点的内存*/
void DestroyQueue(LinkQueue * queue);			/*销毁队列*/
Status ClearQueue(LinkQueue * queue);			//将队列queue清空
Status QueueEmpty(LinkQueue queue);				//判断队列是否为空
Status GetHead(LinkQueue queue ,QElemType * e); //获取队列第一个元素
int QueueLength(LinkQueue queue);				//返回队列长度
Status EnQueue(LinkQueue * queue, QElemType e);	//元素e 插入队列queue
Status DeQueue(LinkQueue * queue ,QElemType * e);  //若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status QueueTraverse(LinkQueue queue);			//遍历队列,对队列的每个元素调用Visit函数



/*以下为单链表的结构和基本操作 的声明*/
typedef struct Event{
	int occurTime;	  //事件发生时刻
	int nType;		  //事件类型,0:到达事件;1到4表示四个窗口的离开事件;
	
}Event,ElemType;	  //单链表的结点:事件

typedef struct LNode{
	ElemType data;		  //单链表的事件(即单链表的元素)
	struct LNode * next;  //下一个结点指针
}LNode;			 //单链表的结点

typedef struct {
	LNode * head;		//头指针
	LNode * rear;		//尾指针
	int length;			//链表长度
}LinkList;				//单链表结构

Status InitList(LinkList * L);						//初始化单链表
void DestroyList(LinkList * L);					//销毁单链表
Status ListInsertByOrder(LinkList * L, Event e);    //将事件e(链表的元素)的发生时间顺序插入到链表中
Status ListEmpty(LinkList  L);						//判断链表是否为空,空返回TRUE,否则返回FALSE;
Status ListDelFstNode(LinkList * L, Event * e);		//从链表中删除首结点,并将结点中的元素(事件)使用 e 返回
Status ListTraverse(LinkList  L);					//遍历链表

6.2 队列函数文件

  第二步,新建队列基本操作的文件 LinkQueue.c

#include <stdio.h>
#include <stdlib.h>
#include "DataStruct.h"

/*初始化队列,申请一个头结点的内存*/
Status InitQueue(LinkQueue * queue)
{
	queue->front=(QNode *) malloc(sizeof(QNode));
	if(queue->front == NULL)
		exit(0);
	queue->front->next = NULL;
	queue->rear = queue->front;
	queue->length = 0;
	return OK;
}

/*销毁队列*/
void DestroyQueue(LinkQueue * queue)
{
	ClearQueue(queue);
	free(queue->front);
	queue->rear=queue->front=NULL;
}

 /* 将队列queue清空*/
Status ClearQueue(LinkQueue * queue)
{
	QNode * curNode;
	while((curNode= queue->front->next)!=NULL)
	{
		queue->front->next = curNode->next;
		free(curNode);
	}
	queue->rear=queue->front;
	queue->length=0;
	return OK;
}
//判断队列是否为空
Status QueueEmpty(LinkQueue queue)
{
	return queue.front == queue.rear? TRUE:FALSE;
}

 //获取队列第一个元素
Status GetHead(LinkQueue queue, QElemType * e)
{
	if(queue.length==0)
		return FALSE;
	*e=queue.front->next->data;
	return TRUE;
}

int QueueLength(LinkQueue queue)
{
	return queue.length;
}

//元素e 插入队列queue
Status EnQueue(LinkQueue * queue, QElemType e)
{
	QNode * curNode;
	curNode=(QNode *)malloc(sizeof(QNode));
	if(curNode == NULL)
	{
		printf("申请空间失败");
		exit(0);
	}
	curNode->data = e ;
	curNode->next = NULL;
	queue->rear->next = curNode;
	queue->rear = curNode;
	queue->length++;
	return TRUE;
}

//若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status DeQueue(LinkQueue * queue ,QElemType * e)
{
	QNode * firstNode;
	if(queue->length == 0)
		return FALSE;
	firstNode=queue->front->next;
	*e=firstNode->data;
	queue->front->next=firstNode->next;
	free(firstNode);
	if(--queue->length==0)
		queue->rear=queue->front;
	return TRUE;
}
//队列遍历
Status QueueTraverse(LinkQueue queue)
{
	QNode * curNode;
	if(queue.length==0)
	{
		printf("队列为空\n");
		return FALSE;
	}
	curNode=queue.front->next;
	while(curNode)
	{
		printf("(编号:%d,达到时间:%d,持续时间:%d) ",curNode->data.number,curNode->data.arrivalTime,curNode->data.duration);
		curNode=curNode->next;
	}
	printf("\n");
	return TRUE;
}

6.3 有序链表函数文件

  第三步,新建有序单链表基本操作函数的文件 LinkList.c

#include <stdio.h>
#include <stdlib.h>
#include "DataStruct.h"

 /*初始化单链表*/
Status InitList(LinkList * list)
{
	list->head=(LNode*) malloc(sizeof(LNode));
	if(list->head == NULL)
		exit(0);
	list->head->next = NULL;
	list->rear=list->head;
	list->length=0;
	return TRUE;
}

 /* 销毁单链表 */
void DestroyList(LinkList * list)
{
	LNode * curNode, * tempNode;
	curNode= list->head->next;
	while(curNode)
	{
		tempNode=curNode;
		curNode=curNode->next;
		free(tempNode);
	}
	free(list->head); //释放头结点
	list->head = list->rear = NULL;
	list->length = 0;
}


/* 将事件e(链表的元素)的发生时间顺序插入到链表中*/
Status ListInsertByOrder(LinkList * list, Event e)
{
	LNode * newNode,*curNode;
	newNode=(LNode *) malloc(sizeof(LNode));
	if(newNode == NULL)
		exit(0);
	newNode->data = e;
	
	if(list->length==0)			//链表为空
	{
		list->rear = list->head->next = newNode;
		newNode->next = NULL;

	}else						//链表不为空,需要循环找到插入位置
	{
		curNode=list->head;
		while(curNode->next != NULL && curNode->next->data.occurTime < e.occurTime) //遍历链表,找到e的合理位置
			curNode=curNode->next;

		if(curNode->next ==NULL) //在链表尾部
			list->rear=newNode;

		newNode->next = curNode->next;
		curNode->next = newNode;
	}
	list -> length++;
	return TRUE;

}

/*判断链表是否为空,空返回TRUE,否则返回FALSE;*/
Status ListEmpty(LinkList  list)
{
	return list.length == 0? TRUE:FALSE;
}

 /*从链表中删除首结点,并将第一个结点使用 node返回 */
Status ListDelFstNode(LinkList * list, Event * e)
{
	LNode * fstNode =list->head->next; //获取第一个结点
	if(ListEmpty(*list))
		return FALSE;
	*e= fstNode->data;
	list->head->next = fstNode->next;
	list->length--;
	if(list->length==0) //如果删除的结点是最后一个结点
		list->rear=list->head;
	free(fstNode);
	return TRUE;
}

/* 遍历链表 */
Status ListTraverse(LinkList  list)
{

	LNode * curNode=list.head->next;
	if(list.length==0){
		printf("链表为空\n");
		return ERROR;
	}
	while(curNode)
	{
		printf("(发生时刻:%d,事件类型:%d),",curNode->data.occurTime,curNode->data.nType);
		curNode = curNode->next;
	}

	return OK;
}

6.4 新建主程序文件

   最后一步,新建银行业务模拟的主程序

#include <stdio.h>
#include <time.h>
#include "DataStruct.h"

int CustomerNumber = 0;	//顾客的编号
int CloseTime = 50 ;	//银行关闭时间,即营业时间长度
int TotalTime = 0;		//所有客户总耗时
LinkQueue queue[4];		//4个队列模拟四个窗口
LinkList  eventList;	//事件链表

/*新建一个客户信息的元素(队列的元素)*/
QElemType NewCustomer(int number, int arrivalTime,int duration);
/*新建一个事件(单链表结点中的数据)*/
ElemType NewEvent(int occurTime,int nType);
/*在队列数组中查找长度最短的队列,并返回其下标*/
int ShortestQueueIndex();
/*打印4个队列*/
void PrintQueues();
//休眠函数
void sleep(float time);
/*销毁链表和队列*/
void DestoryDataStruct();


/*下面4个函数为核心函数*/
/*银行开门营业*/
void OpenForDay();
/*客户到达事件*/
void CustomerArrived(Event en);
/*客户离开*/
void CustomerDeparture(Event en);
/*银行模拟程序*/
void BankSimulation();


/*新建一个客户信息的元素(队列的元素)*/
QElemType NewCustomer(int number, int arrivalTime,int duration)
{
	QElemType e;
	e.number=number;
	e.arrivalTime=arrivalTime;
	e.duration=duration;
	return e;
}

/*新建一个事件(单链表结点中的数据)*/
ElemType NewEvent(int occurTime,int nType)
{
	Event e;
	e.occurTime=occurTime;
	e.nType=nType;
	return e;
}

/*在队列数组中查找长度最短的队列,并返回其下标*/
int ShortestQueueIndex()
{
	int i,minQueueIndex=0;			 //minQueueIndex 最短队列下标
	int minLen=QueueLength(queue[0]);//定义一个最小长度变量
	for(i=1;i<4;i++)
	{
		if(minLen>QueueLength(queue[i])){
			minLen=QueueLength(queue[i]);
			minQueueIndex=i;
		}
	}
	return minQueueIndex;
}

/*打印4个队列*/
void PrintQueues()
{
	int i=0;
	for(;i<4;i++)
	{
		printf("%d 号窗口:",i+1);
		QueueTraverse(queue[i]);
	}
}
//休眠函数
void sleep(float time)
{
   clock_t   now   =   clock(); 
   while( clock() - now < time*1000); 
}

/*销毁链表和队列*/
void DestoryDataStruct()
{
	int i=0;
	DestroyList(&eventList);
	for(;i<4;i++)
	{
		DestroyQueue(&queue[i]);
	}
}

/*银行开门营业,有以下几个功能:
	1. 初始化事件链表,并生成第一个客户到达事件插入链表
	2. 初始化4个队列,用于模拟银行窗口。
*/
void OpenForDay()
{
	int i;
	InitList(&eventList);
	ListInsertByOrder(&eventList, NewEvent(0,0));
	for(i=0;i<4;i++)
		InitQueue(&queue[i]);
}



/*	客户到达事件,主要有以下功能
	1. 生成一个新的客户到达事件,插入到事件链表中
	2. 将事件en中的刚到达客户信息插入到最短的队列中;
	3. 如果队列 插入前是空队列,则生成一个离开事件插入到事件链表中(空队列,说明客户到队列中,业务就立马办理了,无需等待)
*/
void CustomerArrived(Event en)
{	
	int i,duration;	//duration当前到达事件中的客户办理业务的持续时间
	int interTime_newCustomer;   // 新生成客户达到的间隔时间;
	int arrivalTime_newCustomer; //新生成客户的到达事件
	interTime_newCustomer = rand()%5 + 1;//新生成客户到达时间设置5分钟之内
	duration = rand()%30 + 1;			 //当前到达客户业务办理时间在30分钟
	arrivalTime_newCustomer = en.occurTime+interTime_newCustomer ;
	printf("时刻 %d: %d号 客户到达;\n",en.occurTime,++CustomerNumber);
	if(arrivalTime_newCustomer < CloseTime)
	ListInsertByOrder(&eventList,NewEvent(arrivalTime_newCustomer,0)); //生成一个新的客户到达事件插入到事件链表中

	i=ShortestQueueIndex();
	EnQueue(&queue[i],NewCustomer(CustomerNumber,en.occurTime,duration)); //到达客户入列
	if(QueueLength(queue[i])==1)//插入之前是空队列
		ListInsertByOrder(&eventList,NewEvent(en.occurTime+duration,i+1));//生成一个离开事件插入到事件链表中
}

/*客户离开*/
void CustomerDeparture(Event en)
{
	int i=en.nType-1;
	QElemType customer;
	DeQueue(&queue[i],&customer);
	printf("时刻 %d: %d号 客户离开;\n",en.occurTime,customer.number);
	TotalTime += en.occurTime - customer.arrivalTime;
	if(!QueueEmpty(queue[i])){
		GetHead(queue[i],&customer); //从队列中获取下一个客户
		ListInsertByOrder(&eventList,NewEvent(en.occurTime+customer.duration,i+1));//下个客户的离开事件插入事件链表
	}
		
}

void BankSimulation(){
	Event e;
	srand((unsigned)time(NULL));//使用时间生成一个随机种子
	OpenForDay();
	while(!ListEmpty(eventList))
	{
		ListDelFstNode(&eventList, &e);
		if(e.nType==0)
			CustomerArrived(e);
		else 
			CustomerDeparture(e);

		/*下面几行就是打印当前链表和队列*/
		printf("\n事件链表: ");
		ListTraverse(eventList);
		printf("\n\n");
		PrintQueues();
		printf("\n\n");
		sleep(1);//休眠1秒,可以注释掉
	}
	printf("每个客户平均时间:%f",(float)TotalTime/CustomerNumber);
	DestoryDataStruct();//最后销毁链表和数据结构,释放内存空间
}


int main()
{
	BankSimulation();
	getchar();
	return 0;
}

7. 运行结果

在这里插入图片描述

8. 小结

银行业务模拟项目,很好的复习了单链表和队列的使用,并能够对事件驱动模拟有一个很好的理解。

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

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

相关文章

手机天线都去哪里了?

在手机的演变历程中&#xff0c;天线的设计和位置一直是工程师们不断探索和创新的领域。你是否好奇&#xff0c;现在的手机为什么看不到那些曾经显眼的天线了呢&#xff1f; 让我们一起揭开这个谜题。 首先&#xff0c;让我们从基础开始&#xff1a;手机是如何发出电磁波的&…

云手机在跨平台兼容性方面优势明显?有何应用场景

跨平台设备间无缝切换和数据同步的需求现在是很多人或者企业都需要的&#xff0c;云手机在这些方面似乎有很大优势&#xff1f;下面我们来具体探讨在兼容方面&#xff0c;云手机有何出彩之处&#xff1f;又支持哪些应用场景呢 先来说说云手机跨平台兼容性优势所在&#xff0c;要…

web端使用高德地图

web端使用高德地图 一、申请高德key和秘钥二、在项目中引入所需功能js、css文件三、实现地图选点、回显选点四、自定义地图私密限制 一、申请高德key和秘钥 申请高德key 申请成功后可以得到key 二、在项目中引入所需功能js、css文件 <script src"https://webapi.am…

大模型网信办备案全网最详细说明(附附件)

本文共分为以下几个章节 一、大模型算法备案的强制性 二、生成式人工智能(大语言模型)安全评估要点 三、大模型备案必备材料重点说明 四、大模型备案填报流程 五、大模型备案时间成本对比 六、备案建议 附录、过程性材料 一、大模型算法备案的强制性 1、强制要求备案 …

JMeter详解

一、线程组 作用:线程组就是控制Imeter用于执行测试的一组用户 位置:右键点击测试计划’-->添加 -->线程(用户)--> 线程组 特点: 模拟多人操作线程组可以添加多个&#xff0c;多个线程组可以并行或串行取样器(请求)和逻辑控制器必须依赖线程组才能使用线程组下可以…

ECM和MEMS技术在心肺声学监测中的应用

心肺疾病是全球范围内导致死亡的主要原因。因此&#xff0c;对这些疾病迹象的准确和快速评估对于为患者提供适当的医疗保健至关重要。心血管疾病最重要的迹象之一是心脏周期的异常。大多数呼吸系统疾病则表现为呼吸周期的异常。有多种方法可以监测心脏和肺部的周期。听诊是监测…

【面试干货】Java中的访问修饰符与访问级别

【面试干货】Java中的访问修饰符与访问级别 1、public2、protected3、默认&#xff08;没有访问修饰符&#xff09;4、private &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;访问修饰符用于控制类、变量、方法和构造器…

blender 快捷键 常见问题

一、快捷键 平移视图&#xff1a;Shift 鼠标中键旋转视图&#xff1a;鼠标中键缩放视图&#xff1a;鼠标滚动框选放大模型&#xff1a;Shift B 二、常见问题 问题&#xff1a;导入模型成功&#xff0c;但是场景中看不到。 解决办法&#xff1a;视图-裁剪起点&#xff0…

“Docker入门指南:概念与安装详解“

目录 # 概念 1. Docker常见问题 2. docker概念和安装 2.1 Docker的组成 2.2 Docker 组件及关系表 2.3 docker核心思想 2.4 docker镜像与容器两个核心概念 2.5 容器概念图 2.6 docker核心技术 2.6.1 镜像 (Image) 概述 关系 示例 2.6.2 容器 (Container) 概述 关…

贪吃蛇——c语言版

文章目录 演示效果实现的基本功能技术要点源代码实现功能GameStart打印欢迎界面和功能介绍绘制地图创建蛇创建食物 GameRun打印提示信息蛇每走一步 GameEnd蛇死亡后继续游戏 演示效果 贪吃蛇1.0演示视频 将终端应用程序改为控制台主机 实现的基本功能 贪吃蛇地图绘制蛇吃食物的…

[Mysql] 数据库基本概念

前言---数据库系统发展史 当今主流数据库介绍 一、操作系统 Linux操作系统 &#xff1a;RedHat CentOS Debian Ubuntu OpenSUSE 信创标准 会让系统逐渐国产化 国产系统&#xff1a;华为 欧拉 阿里 龙蜥 腾讯 tencentOS 银河麒麟 中标麒麟…

分享:MoneyPrinterTurbo只需一个视频主题或关键词全自动生成一个高清的短视频

MoneyPrinterTurbo是基于原有的MoneyPrinter项目进行优化和重构后推出的新版本。它利用先进的AI技术&#xff0c;通过用户提供的视频主题或关键词&#xff0c;全自动生成视频文案、素材、字幕以及背景音乐&#xff0c;并最终合成高清的短视频。 功能特性 AI智能文案生成&…

redis高可用-主从同步

目录 一&#xff1a;背景 二&#xff1a;实现方式 三&#xff1a;实际使用 一&#xff1a;背景 上一节我们介绍了centos下redis下的安装配置&#xff0c;是在单台服务器部署一个redis服务&#xff0c;这种模式是单机模式下使用的&#xff0c;如果出现服务故障&#xff0c;re…

Spring AI 调用 openAI 进行语音识别

Spring AI支持语音识别功能&#xff0c;目前仅支持OpenAI的Transcription模型。 项目搭建&#xff1a; 参考 Spring AI 介绍以及与 Spring Boot 项目整合 源码示例&#xff1a; RestController RequestMapping("/openai") public class OpenAiIAudioTranscriptionC…

幂集000

题目链接 幂集 题目描述 注意点 集合中不包含重复的元素 解答思路 可以使用深度优先遍历的思想按顺序将相应的元素添加到子集中&#xff0c;并将每个子集添加到结果集 代码 class Solution {public List<List<Integer>> subsets(int[] nums) {List<List&…

VirtualBox虚拟机下安装Ubuntu24.04操作系统

目录 0 背景1 虚拟机的安装1.1 下载安装包1.2 走安装向导 2 操作系统的安装2.1 下载光盘镜像文件2.2 安装操作系统到虚拟机上 3 基本配置3.1 网络连接方式3.2 共享文件夹3.3 设置显存大小 0 背景 首先说说Ubuntu系统&#xff0c;或者更普遍一点&#xff0c;Linux系统究竟有什么…

Java项目学习(员工管理)

新增、员工列表、编辑员工整体代码流程与登录基本一致。 1、新增员工 RestController RequestMapping("/admin/employee")EmployeeController 类中使用了注解 RestController 用于构建 RESTful 风格的 API&#xff0c;其中每个方法的返回值会直接序列化为 JSON 或…

Mirillis Action v4 解锁版安装教程(专业高清屏幕录像软件)

前言 Mirillis Action!&#xff08;暗神屏幕录制软件&#xff09;专业高清屏幕录像软件&#xff0c;被誉为游戏视频三大神器之一。这款屏幕录制软件和游戏录制软件&#xff0c;拥有三大硬件加速技术&#xff0c;支持以超高清视频画质录制桌面和实况直播&#xff0c;超清视频画…

90 Realistic Arctic Environment Textures snow(90+种逼真的北极环境纹理--雪、冰及更多)

一组90多个逼真的雪、冰、雪地岩石和其他被雪覆盖的地面纹理,供在雪地环境中使用。每个纹理都是可贴的/无缝的,并且完全兼容各种不同的场景--标准的Unity地形、Unity标准着色器、URP、HDRP等等都兼容。 所有的纹理都是4096x4096,并包括一个HDRP掩码,以完全支持HDRP。 特点。…

揭示数据库内核的奥秘--手写数据库toadb开源项目

揭示数据库内核的奥秘–手写数据库toadb 数据为王的时代 在信息化时代&#xff0c;数据已成为企业和应用不可或缺的核心&#xff0c;而数据库不仅是数据的仓库&#xff0c;更是支撑业务决策、系统运行的基石。对于求职者而言&#xff0c;掌握数据库知识已成为求职市场上的必考…