1. 의미
- 큐(Queue)의 사전적 의미는 무엇을 기다리기 위해 서는 줄, 대기열입니다.
예를들어 우리가 게임을 할 때 '큐를 잡는다, 큐를 기다린다'라는 말의 큐는 바로 줄, 대기열을 의미합니다. 우리가 줄을 서면 가장 앞에있는 사람(가장 먼저 들어온 데이터)이 가장 먼저 들어가죠? 이러한 구조를 선입선출(First In First Out; FIFO)구조라고 합니다. 

2. 연산
- 일반적으로 큐 자료구조의 앞을 Front, 뒤를 Rear라고 칭합니다. 그림으로 표현하면 다음과 같습니다.


큐가 비어있는 상태를 front == rear(같음) 상태로 표현합니다.
(초기화시 front = rear = 0으로 초기화)



삽입(Enqueue)연산은 rear의 위치에 데이터를 삽입하고 rear의 위치를 1 증가 시켜줍니다.



삭제(Dequeue)연산은 front 위치의 데이터를 반환하고 front의 위치를 1 증가 시켜줍니다.
이러면 front와 rear가 같은 값이 되므로 다시 큐가 비어있는 상태가 됩니다.



큐의 끝(rear)가 배열의 마지막을 가리키고있는 상태가 큐가 가득 찬 상태입니다.
이렇게 큐를 배열로 구현했을 경우 0번 인덱스는 사용하지 않는 메모리가 되었습니다.
물론 고정적인 배열의 크기도 문제가 됩니다.
이를 해결하기 위해 원형 큐, 링크드 리스트로 구현한 큐... 등 여러가지 큐가 존재합니다.

3. 사용
프로세스 관리
운영체제(OS)의 작업 큐
프린터 출력의 문서 대기...등 
입력된 시간 순서대로 처리해야하는 모든 상황에 거의 큐가 사용됩니다.

4. 구현
배열로 구현한 큐)
#include <iostream> 
using namespace std;

class queue
{
private:
     int *queue_arr; // 큐 배열(동적 할당을 위해 포인터로 선언) 
     int queue_size; // 큐의 크기 
     int 
front, rear;

public:
     queue() // 디폴트 생성자 함수 
     {
          
front = 0; rear = 0// front와 rear 위치를 0으로 초기화
          queue_size = 5// 매개변수 없이 객체 생성 시 스택 크기 5로 지정 
          queue_arr = new int[queue_size]; // 배열 동적 할당 
          for (int i = 0; i < queue_size; i++)
          {
               queue_arr[i] = 0// 큐의 배열은 모두 0으로 초기화 
          }
     }
     queue(int 
size// 생성자 함수 
     {
          front = 0; rear = 0// front와 rear 위치를 0으로 초기화
          queue_size = 
size// 입력한 매개변수 크기만큼 스택 크기 지정 
          queue_arr = new int[queue_size]; // 배열 동적 할당 
          for (int i = 0; i < queue_size; i++)
          {
               queue_arr[i] = 0// 큐의 배열은 모두 0으로 초기화 
          }
     }
     ~queue() // 소멸자 함수 
     {
          delete[] queue_arr;
     }
     void enqueue(int data) // 삽입 함수 
     {
          if (queue_is_full()) // 큐가 가득 차 있는 경우 
          {
               cout << "큐가 가득 차 있습니다." << "\n";
               return// 함수 종료 
          }
          else // 아닐 경우
          {
               queue_arr[rear++= data;
               // 큐 배열 rear 위치의 데이터를 삽입 후 rear의 크기 1 증가
               // 위 코드가 이해가지 않는다면 후위 증감 연산자에 대해 공부할 것
               cout << "데이터 삽입 성공!" << "\n";
          }
     }
     void dequeue() // 삭제 함수 
     {
          if (queue_is_empty()) // 큐가 비어있는 경우 
          {
               cout << "큐가 비어있습니다." << "\n";
               return// 함수 종료 
          }
          else // 아닐 경우 
          {
               cout << "반환 된 데이터 : " << queue_arr[front<< "\n"// 데이터 반환 
               queue_arr[front++= 0
               // 큐 배열 front 위치의 데이터를 삭제 후 front 크기 1 증가
          }
     }
     bool queue_is_empty() // 큐가 비어있는지 확인 함수 
     {
          if (front == rear) // front와 rear가 같은 위치라면
               return true;
          else // 아닐 경우 비어있지 않음 
          return false;
     }
     bool queue_is_full() // 큐가 가득 차 있는지 확인 함수 
     {
          if (rear == queue_size - 1// rear가 큐 배열의 마지막 위치라면
               return true;
          else // 아닐 경우 가득 차 있지 않음 
               return false;
     }
     void print_queue() // 큐 배열 전체 출력 함수 
     {
          cout << "Queue : [ ";
          for (int i = 0; i < queue_size; i++)
          {
               if (i != queue_size - 1)
               {
                    cout << queue_arr[i] << " , ";
               }
               else
               {
                    cout << queue_arr[i];
               }
          }
     cout << " ] " << "\n";
     cout << "front 위치 : " << front << "\n";
     cout << "rear 위치 : " << rear << "\n";
     }
};

int main()
{
     queue *que;
     int input_size;
     cout << "큐 배열 크기 입력 : ";
     cin >> input_size;
     if (input_size <= 0)
     {
          cout << "잘못 된 입력입니다. 디폴트 사이즈(5)로 생성합니다." << "\n";
          que = new queue();
     }
     else
     {
          que = new queue(input_size);
     }
     while (1)
     {
          int input;
          cout << "\n" << "[명령어 입력]" << "\n";
          cout << "1. ENQUEUE " << "\n" << "2. DEQUEUE " << "\n" << "3. PRINT " << "\n" << "4. EXIT : ";
          cin >> input;
          switch (input)
          {
          case 1:
               int input_data;
               cout << "삽입 할 데이터를 입력하세요 : ";
               cin >> input_data;
               que->enqueue(input_data);
               break;
          case 2:
               que->dequeue();
               break;
          case 3:
               que->print_queue();
               break;
          case 4:
               cout << "프로그램을 종료합니다." << "\n";
               return 0;
          default:
               cout << "잘못 된 입력입니다. 다시 입력해 주세요" << "\n";
          }
     }     
}

질문 사항은 댓글로 남겨주세요!



1. 의미
- 스택 자료구조는 아래가 막혀있는 긴 통에 물건을 층층이 쌓아둔 상태로 보시면 됩니다. 
예를들어 물건을 쌓기위해서는 현재 쌓여있는 물건 중 가장 위쪽에 쌓일 것이고, 꺼내기 위해서는 현재 쌓여있는 물건 중 가장 위쪽 물건이 꺼내질 것입니다. 이러한 구조를 선입후출(First In Last Out; FILO)또는 후입선출(Last In First Out; LIFO) 구조라고 칭합니다.

2. 연산
- 스택 자료구조의 연산(삽입, 삭제, 읽기)은 모두 스택의 꼭대기에서 일어납니다. 스택의 꼭대기를 가리키는 변수를 통상적으로 top이라고 합니다.


top이 -1을 가리키고 있는 상태가 스택이 비어있는 상태입니다.
(이해를 돕기위해 -1 인덱스를 표기한 것이지 배열의 인덱스는 0에서 시작합니다.)

삽입(push) 연산은 top이 가리키는 위치를 1 증가시키고, 그 위치에 데이터를 삽입합니다.


top이 인덱스 맨 끝을 가리키고 있는 상태가 스택이 가득 찬 상태입니다.
(인덱스 맨 끝은 스택 사이즈 -1입니다. 인덱스가 0부터 시작하기 때문)


삭제(pop) 연산은 top이 가리키는 위치의 데이터를 반환하고, 위치를 1 감소합니다.

3. 사용
- 스택은 컴퓨터 구조에서 다음과 같이 다양하게 사용됩니다. 

브라우저에서 이전페이지, 다음페이지 이동
에디터에서 실행취소, 다시실행
괄호검사
역순문자열 만들기
후위 표기법 수식의 연산 등...

아래의 구현방법을 통해 실제 스택 사용 예를 직접 구현해 보는것도 자료구조의 이해와 실력 향상에 도움이 될 것입니다.

4. 구현
C++ Class를 이용해 스택 자료구조를 배열로 구현했습니다.

#include <iostream> 
using namespace std; 

class stack 

private : 
     int *stack_arr; 
// 스택 배열(동적 할당을 위해 포인터로 선언) 
     int stack_size;
 // 스택의 크기 
     int top = -1; 
// top은 -1로 초기화  

public : 
     stack() 
// 디폴트 생성자 함수 
     
          stack_size = 5; 
// 매개변수 없이 객체 생성 시 스택 크기 5로 지정 
          stack_arr = new int[stack_size]; 
// 배열 동적 할당 
          for (int i = 0; i < stack_size; i++) 
          
               stack_arr[i] = 0;
 // 스택의 배열은 모두 0으로 초기화 
          
     
     stack(int size) 
// 생성자 함수 
     
          stack_size = size; 
// 입력한 매개변수 크기만큼 스택 크기 지정  
          stack_arr = new int[stack_size]; 
// 배열 동적 할당 
          for (int i = 0; i < stack_size; i++) 
          
               stack_arr[i] = 0; 
// 스택의 배열은 모두 0으로 초기화 
          
     
     ~stack() 
// 소멸자 함수 
     
          delete[] stack_arr; 
     
     void push(int data) 
// 삽입 함수 
     
          if (stack_is_full()) 
// 스택이 가득 차 있는 경우 
          
               cout << "스택이 가득 차 있습니다." << "\n"; 
               return;
 // 함수 종료 
          
          else 
// 아닐 경우 정상 작동 
          
               top++; 
// top 위치 1 증가 
               stack_arr[top] = data; // 데이터 삽입 
               cout << "데이터 삽입 성공!" << "\n"; 
          
     
     void pop() 
// 삭제 함수 
     
          if (stack_is_empty()) 
// 스택이 비어있는 경우 
          
               cout << "스택이 비어있습니다." << "\n"; 
               return; 
// 함수 종료 
          
          else 
// 아닐 경우 
          
               cout << "반환 된 데이터 : " << stack_arr[top] << "\n"; 
// 데이터 반환 
               stack_arr[top] = 0; 
// 데이터 삭제 
               top--; 
// top 위치 1 감소 
          
     
     int peak() 
// 현재 꼭대기 위치 확인 함수 
     
          return stack_arr[top]; 
     
     bool stack_is_empty()
 // 스택이 비어있는지 확인 함수 
     
          if (top == -1)
 // top이 -1을 가리키면 비어있음 
               return true;  
          else 
 // 아닐 경우 비어있지 않음 
               return false; 
     
     bool stack_is_full() 
// 스택이 가득 차 있는지 확인 함수 
     
          if (top == stack_size - 1) 
// top이 인덱스 마지막을 가리키면 가득 차 있음 
               return true; 
          else 
 // 아닐 경우 가득 차 있지 않음 
               return false; 
     
     void print_stack() 
// 스택 전체 출력 함수 
     
          cout << "STACK : [ "; 
          for (int i = 0; i < stack_size; i++) 
          
               if (i != stack_size - 1) 
               
                    cout << stack_arr[i] << " , "; 
               
          else 
          
               cout << stack_arr[i]; 
          
     
     cout << " ] " << "\n"; 
     cout << "top 위치 : " << top << "\n"; 
     
}; 

int main()  

     stack *stk; 
     int input_size; 
     cout << "스택 크기 입력 : "; 
     cin >> input_size; 
     if (input_size <= 0) 
     
          cout << "잘못 된 입력입니다. 디폴트 사이즈(5)로 생성합니다." << "\n"; 
          stk = new stack(); 
     
     else 
     
          stk = new stack(input_size); 
     
     while (1) 
     
          int input; 
          cout << "\n" << "[명령어 입력]" << "\n"; 
          cout << "1. PUSH " << "\n" << "2. POP " << "\n" << "3. PEAK "  
          << "\n" << "4. PRINT " << "\n" << "5. EXIT : "; 
          cin >> input; 
          switch (input) 
          
          case 1: 
               int input_data; 
               cout << "삽입 할 데이터를 입력하세요 : "; 
               cin >> input_data; 
               stk->push(input_data); 
               break; 
          case 2: 
               stk->pop(); 
               break; 
          case 3: 
               cout << "현재 top 위치의 데이터 : " << stk->peak() << "\n"; 
               break; 
          case 4: 
               stk->print_stack(); 
               break; 
          case 5: 
               cout << "프로그램을 종료합니다." << "\n"; 
               return 0; 
          default : 
               cout << "잘못 된 입력입니다. 다시 입력해 주세요" << "\n"; 
          
     
}


질문 사항은 댓글로 남겨주세요!




본 게시글은 Visual Studio 2017 및 OpenCV 2.4.10 버전 기준으로 작성되었음을 알려드립니다.


* 설치하기
1. https://opencv.org/releases.html 링크에 접속합니다.

2. 2.4.10 버전의 win pack을 다운받고 압축을 풉니다. 
   (경로 상관없이 외워두시기만 하면 됩니다.)

3. Visual Studio 2017을 실행합니다.

4. C# Windows Forms 앱으로 프로젝트를 생성합니다.

4-1. 프로젝트를 한번 실행해줍니다.(Ctrl + F5)

5. 생성한 c# 프로젝트 폴더로 이동합니다.

6. 프로젝트 폴더 - bin - debug 에 2번에 풀었던 압축 파일을 모두 복사해줍니다.

7. 다시 Visual Studio로 돌아와서 솔루션 탐색기 - 참조 - 우클릭 - 참조 추가

8. 아래측 찾아보기 버튼을 누르고 6번에 복사해준 폴더로 이동합니다.

9. OpenCV ~ 5개의 dll 파일을 선택하고 추가해줍니다.


10. 확인을 누르면 Visual Studio 2017 C# 환경에서 OpenCV 라이브러리를 사용할 
     준비가 완료되었습니다.


질문사항은 댓글로 달아주세요!



'C#' 카테고리의 다른 글

C# 기초다지기 - 문자열  (2) 2018.11.07
C# 기초다지기 - 배열  (1) 2018.11.06
C# 기초다지기 - 상수  (0) 2018.11.06
C# 기초다지기 - 캡슐화  (0) 2018.11.05
C# 기초다지기 - 프로그램 구조  (0) 2018.11.05
C# 기초다지기 - 변수  (0) 2018.11.05
C# DB연동  (1) 2018.08.29
[C#] 유니코드 한글로 변환하기  (0) 2018.08.22

to Top