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

目录

  • 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 0typedef  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.mzph.cn/diannao/31393.shtml

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

相关文章

Redis精要

一、什么是缓存击穿、缓存穿透、缓存雪崩&#xff1f; 缓存穿透 【针对大量非法访问的请求&#xff0c;缓存中没有&#xff0c;直接访问DB】 缓存穿透指的查询缓存和数据库中都不存在的数据&#xff0c;这样每次请求直接打到数据库&#xff0c;就好像缓存不存在 一样。 对于系…

JVM-GC-常用调优命令和GC参数

定位问题常用命令 top&#xff1a;查看内存/CPU占用情况top -Hp pid: 查看进程内线程情况jsp:查看java进程情况jstack 线程pid:查看进程内线程信息&#xff0c;一般查看线程状态&#xff0c;判断是否死锁。重点观察&#xff1a;WAITING、BLOCKED的线程&#xff0c;另外查看wait…

全面的WAS存储权限管理方案,了解一下

WAS存储权限管理通常指的是对Windows Azure Storage&#xff08;WAS&#xff09;的存储设备进行权限控制和管理。在企业中&#xff0c;随着数据量的飞速增长&#xff0c;对存储设备的安全性、效率和成本的关注也日益增加。有效的WAS存储权限管理可以确保数据的安全性&#xff0…

UV胶带和UV胶水的应用场景有哪些不同吗?

UV胶带和UV胶水的应用场景有哪些不同吗? UV胶带和UV胶水的应用场景确实存在不同之处&#xff0c;以下是详细的比较和归纳&#xff1a; 一&#xff1a;按使用场景来看&#xff1a; UV胶带的应用场景&#xff1a; 包装行业&#xff1a;UV胶带在包装行业中常用于食品包装、药…

深圳比创达电子|EMC与EMI一站式解决方案:源头到终端的全面防护

随着电子技术的飞速发展&#xff0c;电磁兼容性&#xff08;EMC&#xff09;和电磁干扰&#xff08;EMI&#xff09;问题日益成为产品研发和生产的关键因素。为了帮助企业更好地应对这些挑战。 一、EMC与EMI的基本概述 电磁兼容性&#xff08;EMC&#xff09;是指设备或系统在…

【Linux】ss 命令使用详解

目录 一、ss命令介绍 二、ss命令格式和使用 1、命令格式 2、ss命令的常用选项 3、命令的常见用法 3.1 找出打开套接字/端口应用程序 3.2 检查系统的监听套接字 3.3 显示所有状态为established的SMTP连接 3.4 查看建立的 TCP 连接 3.5 通过 -r 选项解析 IP 和端口号 …

12通道温振信号采集卡

12 通道智能数据采集器&#xff0c;以下简称 SG-Vib-S12。 SG-Vib-S12 旨在帮助用户对工业生产中的设备健康状况进行监测与诊断&#xff0c; 降低因设备故障对生产过程产生的影响。SG-Vib-S12 输入同时兼容 IEP、ICP 两 线制、三线制&#xff08;振温一体&#xff09;传感器&…

【html】如何利用hbuilderX 开发一个自己的app并安装在手机上运行

引言&#xff1a; 相信大家都非常想开发一款自己的apk&#xff0c;手机应用程序&#xff0c;今天就教大家&#xff0c;如何用hbuilderX 开发一个自己的app并安装在手机上运行。 步骤讲解&#xff1a; 打开hbuilderX &#xff0c;选择新建项目 2.选择5app,想一个名字&#x…

js三元图的画法

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>三元图</title></head> <body>&l…

爬虫超详细介绍

爬虫&#xff08;Spider&#xff09;是一种自动化程序&#xff0c;用于在互联网上获取信息。 其工作原理主要可以分为以下几个步骤&#xff1a; 发起请求&#xff1a; 爬虫首先需要向目标网站发起HTTP请求&#xff0c;以获取网页的内容。这个请求可以包含一些额外的信息&…

使用 Java 构建和消费 RESTful 服务的基本方法

REST&#xff08;Representational State Transfer&#xff09;是一种架构风格&#xff0c;它基于Web标准和HTTP协议&#xff0c;常用于构建网络服务。使用Java构建和消费RESTful服务需要掌握一些基本概念和技术。 一、RESTful服务的基本概念 1. REST架构风格 REST架构风格的…

NGINX_二十 nginx 监控

二十 nginx 监控 1 nginx的基础监控 进程监控端口监控 注意&#xff1a; 这两个是必须要加在zabbix监控&#xff0c;加触发器有问题及时告警。 web 服务器 nginx 以其高性能与抗并发能力越来越多的被用户使用 作为一款服务器产品&#xff0c;其运行状态是运维密切关注的&a…

【机器学习 复习】第3章 K-近邻算法

一、概念 1.K-近邻算法&#xff1a;也叫KNN 分类 算法&#xff0c;其中的N是 邻近邻居NearestNeighbor的首字母。 &#xff08;1&#xff09;其中K是特征值&#xff0c;就是选择离某个预测的值&#xff08;例如预测的是苹果&#xff0c;就找个苹果&#xff09;最近的几个值&am…

项目六 OpenStack虚拟机实例管理

任务一 理解OpenStack计算服务 1.1 •什么是Nova • Nova是OpenStack中的计算服务项目 &#xff0c;计算虚拟机实例生命周期的所有活动都由 Nova 管理 。 • Nova 提供统一的计算资源 服务。 • Nova 需要下列 OpenStack 服务的 支持。 Keystone &#xff1a;为所有的 OpenSt…

单商户社区团购卖菜卖水果商城自提点商城系统小程序源码

打造便捷团购新体验 &#x1f34e; 引言&#xff1a;社区团购的崛起 近年来&#xff0c;社区团购以其独特的优势&#xff0c;迅速崛起并受到广大消费者的喜爱。它不仅能够提供物美价廉的商品&#xff0c;还能让居民们享受到更加便捷的购物体验。而单商户社区团购系统小程序&am…

详解 HBase 的架构和基本原理

一、基本架构 StoreFile&#xff1a;保存实际数据的物理文件&#xff0c;StoreFile 以 HFile 的格式 (KV) 存储在 HDFS 上。每个 Store 会有一个或多个 StoreFile&#xff08;HFile&#xff09;&#xff0c;数据在每个 StoreFile 中都是有序的MemStore&#xff1a;写缓存&#…

【YOLOv5/v7改进系列】引入特征融合网络——ASFYOLO

一、导言 ASF-YOLO结合空间和尺度特征以实现精确且快速的细胞实例分割。在YOLO分割框架的基础上&#xff0c;通过引入尺度序列特征融合(SSFF)模块来增强网络的多尺度信息提取能力&#xff0c;并利用三重特征编码器(TFE)模块融合不同尺度的特征图以增加细节信息。此外&#xff…

信息打点web篇----web后端源码专项收集

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 专栏描述&#xff1a;因为第一遍过信息收集的时候&#xff0c;没怎么把收集做回事 导致后来在实战中&#xff0c;遭遇资产获取少&#xff0c;可渗透点少的痛苦&#xff0c;如今决定 从头来过&#xff0c;全面全方位…

手把手教你实现条纹结构光三维重建(3)——相机投影仪标定

我们都知道&#xff0c;投影仪其实就是个反向相机&#xff0c;如果我们了解双目标定的原理&#xff0c;那么相机和投影仪的标定就不难&#xff0c;关键是我们怎么得到投影仪在图像特征点&#xff08;比如棋盘格角点&#xff09;上的像素位置。 投影仪也类似于一个cmos&#xf…

WebSocket实现消息实时通知

参考文档&#xff1a;万字长文&#xff0c;一篇吃透WebSocket&#xff1a;概念、原理、易错常识、动手实践、WebSocket 教程 1 背景 有一个需求&#xff0c;需要实现实时通信的功能&#xff0c;如果有新消息&#xff0c;后端会主动发送请求告知前端有新消息&#xff0c;需要前…