시뮬레이션이란?
- 실제로 일을 실행하기에 앞서서 프로그램으로 미리 실험하는 것이다.
- 주어진 문제를 수학적으로 모델링하는 데에서 시작한다.
- 고객의 평균 도착시간은?
- 고객은 보통 몇 분에 한 명씩 은행에 도착하는가?
- 한 고객당 처리 시간은 몇 분 정도 걸리는가?
시간중심(time-driven) 시뮬레이션
시뮬레이션 시계에 일정 단위 시간(tick)을 계속적으로 증가시키면서 매번 해당 시간에 일어나는 일이 있는지를 검사하면서 시뮬레이션한다.
사건중심(event-driven) 시뮬레이션
시물레이션의 대상이 되는 사건이 발생할 때마다 경과된 시간을 증가시키고 상태 변수들을 갱신하면서 시뮬레이션한다.
예) 은행 창구 시뮬레이션
- 고객의 도착, 서비스 시작, 서비스 종료의 3가지 사건(이벤트)
고객의 표현
- 평균 간격을 갖도록 한 난수함수를 이용해 도착시간을 구한다.
- 평균 서비스시간을 갖도록 난수함수를 이용해 서비스시간을 구한다.
- 주어진 시간 간격으로 고객이 발생순서대로(큐) 은행 대기열에 삽입된다.
대기열
- 원형 연결리스트를 이용해 큐를 구현한다.
- 큐의 원소는 고객을 가지고 insert 와 delete 함수를 제공한다.
은행직원
- 대기열(큐)에서 고객을 1명 꺼내서 서비스 창구에서 서비스한다.
- 서비스 시작시간(ServiceStartTime)을 이용해서 해당고객이 기다린 시간(WaitingTime)을 계산한다.
- 서비스종료시간(다음 고객의 서비스 시작 시간)을 계산한다.
- 서비스한 고객의 수와 고객의 총 대기 시간 등을 계산한다.
시뮬레이션 프로그램 작동 순서
1. 고객의 도착 시간을 임의로 발생시켜 대기열에 넣는다.
2. 큐에서 1명씩 고객을 꺼내서 대기 시간을 계산하고, 다음 고객의 서비스 시작 시간을 구한다.
3. 큐의 고객이 모두 없어질 때까지 반복한다.
4. 고객의 총 방문 수, 총 대기시간, 평균대기시간을 계산하고 종료한다.
1. 은행 영업 마감 시간이 될 때까지 반복
1.1. 고객의 도착시간 계산
1.2. 고객의 서비스 시간 계산
1.3. 고객을 대기열에 넣는다.
2. 대기열이 빌 때까지 반복
2.1. 고객 데이터를 큐에서 꺼낸다.
2.2. 창구 서비스 시작 시간이 고객이 도착한 시간을 비교
2.2.1. 서비스 시작 시간이 빠르거나 같으면 - 고객대기시간 = 0
- 서비스 시작 시간 = 고객 도착 시간
2.2.2. 서비스 시작 시간이 도착한 시간보다 늦으면 - 고객대기 시간 = 서비스 시작시간 - 고객이 도착한 시간
2.3. 다음 서비스 시작 시간 = 서비스 시작 시간 + 고객 서비스 시간
3. 분석 및 결과 출력
3.1. 총 서비스를 받은 고객의 수 계산
3.2. 고객의 총 대기 시간 계산
3.3. 고객의 평균 대기시간 = (총 대기시간)/(고객의 수)
은행창구 시뮬레이션 구현
#include <stdio.h>
#include <stdlib.h>
#define ConstCloseTime 120 // 업무시간 2시간으로 가정
#define ConstMaxInterval 5 // 0~4분 간격으로 랜덤하게 도착
#define ConstMaxSvcTime 10 // 서비스 시간은 1~9분으로 랜덤하게 발생
// 고객 정의
typedef struct {
int ArrivalTime; // 고객의 도착 시간
int ServiceTime; // 서비스 소요시간
} customerType;
// 고객리스트 정의 - 연결리스트로 구현한 큐
typedef struct node {
customerType Customer; // 고객 데이터 저장
struct node* next; // 다음 고객 가리키는 링크
}nodeType;
// Front, Rear를 가리키는 포인터 선언
nodeType* Front;
nodeType* Rear;
// 서비스 통계 정의
typedef struct {
int CustomerNumber;
int ServiceStartTime;
int WaitingTime;
int TotalWaitingTIme;
float AvgWaitingTIme;
} serverType;
void init() {
Front = NULL;
Rear = NULL;
}
int isEmpty() {
return (Front == NULL);
}
void insert(customerType NewCustomer) {
// 삽입할 고객(신규생성 고객노드)를 임시 포인터 ptr가 가리킨다.
nodeType* ptr = (nodeType*)malloc(sizeof(nodeType));
ptr->Customer = NewCustomer;
ptr->next = NULL;
// 빈큐이면 Front, Rear 모두 생성된 노드를 가리킨다.
// 두번째 노드부터는 Rear 뒤에 삽입
if (isEmpty()) {
Front = ptr;
Rear = ptr;
}
else {
Rear->next = ptr;
Rear = ptr;
}
}
customerType del() {
nodeType* ptr;
customerType temp_data;
if (isEmpty()) {
printf("큐가 비어있습니다.\n");
temp_data.ArrivalTime = -1;
temp_data.ServiceTime = -1;
return temp_data;
}
else {
ptr = Front;
Front = Front->next;
temp_data = ptr->Customer;
free(ptr);
return(temp_data);
}
}
#include <stdio.h>
#include <stdlib.h>
#include "bank.h"
// 서비스 창구가 1개인 경우
void main() {
int CustomerArrivalTime = 0; // 도착시간 저장을 위한 임시 변수
customerType c1; // 고객정보를 다루기 위한 변수
// 서비스 정보를 다루기 위한 변수 선언 및 초기화
serverType s1;
s1.CustomerNumber = 0; // 총 고객의 수
s1.WaitingTime = 0; // 고객 대기 시간
s1.TotalWaitingTIme = 0; // 고객 총 대기시간
s1.AvgWaitingTIme = 0; // 고객 평균대기시간
s1.ServiceStartTime = 0; // (다음)서비스 시작 시간
init(); // 대기열 초기화
// 은행에 도착하는 고객을 임의로 생성하여 큐에 모두 넣는다.
// 처음 도착한 고객의 시간(0~9분의 값을 가진다)
CustomerArrivalTime = rand() % ConstMaxInterval;
while (CustomerArrivalTime <= ConstCloseTime) // 영업 종료 시간이 넘기 전까지만
{
c1.ArrivalTime = CustomerArrivalTime; // 고객의 도착시간
c1.ServiceTime = rand() % ConstMaxSvcTime + 1; // 서비스 시간 : 1분에서 5분 사이
insert(c1); // 대기열에 넣는다.
// 다음 고객이 도착하는 시간을 계산해서 구한다.
CustomerArrivalTime = CustomerArrivalTime + (rand() % ConstMaxInterval);
}
while (!isEmpty()){
// 고객을 1명 꺼내옴
c1 = del();
s1.CustomerNumber = s1.CustomerNumber + 1; // 고객의 수 증가
// 고객이 기다리는 경우 대기시간 계산
if (s1.ServiceStartTime >= c1.ArrivalTime) {
s1.WaitingTime = s1.ServiceStartTime - c1.ArrivalTime; // 기다린 시간
s1.TotalWaitingTIme = s1.TotalWaitingTIme + s1.WaitingTime; // 기다린 시간 누적
printf("%d번째 고객의 대기시간은 %d분 입니다.\n", s1.CustomerNumber, s1.WaitingTime);
}
else {
// 서비스 시작 시간을 고객 도착 시간으로 재설정
s1.ServiceStartTime = c1.ArrivalTime;
printf("%d번째 고객의 대기시간은 0분 입니다.\n", s1.CustomerNumber);
}
// 다음 고객의 서비스 시작 시간 계산
s1.ServiceStartTime = s1.ServiceStartTime + c1.ServiceTime;
}
s1.AvgWaitingTIme = (float)s1.TotalWaitingTIme / (float)s1.CustomerNumber;
printf("방문한 고객의 총 수는 %d명 입니다.\n", s1.CustomerNumber);
printf("방문한 고객의 총 대기시간은 %d분 입니다.\n", s1.TotalWaitingTIme);
printf("방문한 고객의 평균 대기시간은 %f분 입니다.\n", s1.AvgWaitingTIme);
}
1번째 고객의 대기시간은 0분 입니다.
2번째 고객의 대기시간은 4분 입니다.
3번째 고객의 대기시간은 1분 입니다.
4번째 고객의 대기시간은 3분 입니다.
5번째 고객의 대기시간은 10분 입니다.
6번째 고객의 대기시간은 15분 입니다.
7번째 고객의 대기시간은 20분 입니다.
8번째 고객의 대기시간은 27분 입니다.
9번째 고객의 대기시간은 29분 입니다.
10번째 고객의 대기시간은 30분 입니다.
11번째 고객의 대기시간은 36분 입니다.
12번째 고객의 대기시간은 39분 입니다.
13번째 고객의 대기시간은 41분 입니다.
14번째 고객의 대기시간은 43분 입니다.
15번째 고객의 대기시간은 47분 입니다.
16번째 고객의 대기시간은 51분 입니다.
17번째 고객의 대기시간은 57분 입니다.
18번째 고객의 대기시간은 62분 입니다.
19번째 고객의 대기시간은 63분 입니다.
20번째 고객의 대기시간은 73분 입니다.
21번째 고객의 대기시간은 75분 입니다.
22번째 고객의 대기시간은 75분 입니다.
23번째 고객의 대기시간은 76분 입니다.
24번째 고객의 대기시간은 80분 입니다.
25번째 고객의 대기시간은 79분 입니다.
26번째 고객의 대기시간은 86분 입니다.
27번째 고객의 대기시간은 89분 입니다.
28번째 고객의 대기시간은 95분 입니다.
29번째 고객의 대기시간은 102분 입니다.
30번째 고객의 대기시간은 100분 입니다.
31번째 고객의 대기시간은 108분 입니다.
32번째 고객의 대기시간은 114분 입니다.
33번째 고객의 대기시간은 114분 입니다.
34번째 고객의 대기시간은 121분 입니다.
35번째 고객의 대기시간은 120분 입니다.
36번째 고객의 대기시간은 128분 입니다.
37번째 고객의 대기시간은 134분 입니다.
38번째 고객의 대기시간은 144분 입니다.
39번째 고객의 대기시간은 144분 입니다.
40번째 고객의 대기시간은 143분 입니다.
41번째 고객의 대기시간은 148분 입니다.
42번째 고객의 대기시간은 148분 입니다.
43번째 고객의 대기시간은 152분 입니다.
44번째 고객의 대기시간은 152분 입니다.
45번째 고객의 대기시간은 158분 입니다.
46번째 고객의 대기시간은 163분 입니다.
47번째 고객의 대기시간은 172분 입니다.
48번째 고객의 대기시간은 174분 입니다.
49번째 고객의 대기시간은 180분 입니다.
50번째 고객의 대기시간은 179분 입니다.
51번째 고객의 대기시간은 178분 입니다.
52번째 고객의 대기시간은 180분 입니다.
53번째 고객의 대기시간은 185분 입니다.
54번째 고객의 대기시간은 184분 입니다.
55번째 고객의 대기시간은 188분 입니다.
56번째 고객의 대기시간은 194분 입니다.
57번째 고객의 대기시간은 196분 입니다.
58번째 고객의 대기시간은 199분 입니다.
방문한 고객의 총 수는 58명 입니다.
방문한 고객의 총 대기시간은 5908분 입니다.
방문한 고객의 평균 대기시간은 101.862068분 입니다.
'Programming > Data Structure' 카테고리의 다른 글
[C언어] 이중원형연결리스트 (0) | 2022.04.22 |
---|---|
원형연결리스트 (0) | 2022.04.20 |
[C언어] 스택의 응용 (후위표현식) (0) | 2022.04.19 |
[C언어] 스택 연결리스트 자료구조 구현하기 (0) | 2022.04.17 |
[C언어] 연결리스트(링크드리스트) 자료구조 구현 (0) | 2022.04.16 |