C++기초

220413_자료구조_배열형 큐(써클 큐, Circle Queue) 구현 및 실행

hyrule 2022. 4. 18. 14:54
//QueueArray.h

#pragma once

#include <assert.h>

/*
* 일반적인 배열로 큐를 만들어버리면 매우 비효율적이다.
큐는 앞에서 데이터를 꺼내고 뒤에 넣는 형식이기 때문에
계속 데이터의 시작점이 뒤로 밀리기 때문이다.

--> 그래서 배열로 큐를 만들 때는 '써클 큐' 방식으로 만든다.

* 구현 방법: '헤드'와 '테일'을 만들어서 사용한다.
데이터를 꺼낼 때는 헤드에서 꺼낸 뒤 헤드를 뒤로 한 칸 밀고,
데이터를 넣을 때는 테일에 넣은 뒤 테일을 뒤로 한 칸 민다.

* 배열의 끝에 갔을 경우, 다시 앞으로 되돌아 올 수 있어야 한다. 
예를 들어 크기가 6인 배열일 경우, 6번째 칸(인덱스 5)에 다다르면
다시 0으로 돌아가야 한다
--> 구현 방법 : 나머지 연산자(%) -> 6 나머지는 1~5까지만 나오기 때문.  

* 주의)서클 큐에는 헤드 테일이 한 바퀴를 돌아 다시 만났는지
확인해야 하는 빈 공간이 하나 필요하다.
--> 그러므로 길이가 6인 배열에서 실제 데이터를 넣을 수 있는 공간은 5개이다.
--> 헤드를 빈 공간으로 하고, 실제 데이터는 헤더 + 1부터 들어가도록 할 것임.

* 서클 큐를 만들 때 원하는 사이즈만큼의 배열을 할당하는 방법
	- 비타입 템플릿 인자를 사용한다
	- template <typename T, int SIZE = 100> 
	- 함수의 디폴트 인자와 비슷한 기능이라고 보면 된다.
	- 실제 클래스를 사용할 때는
	- CCircleQueue<int>: SIZE = 기본값(100)
	- CCircleQueue<int, 200>: SIZE = 200
*/


template <typename T, int SIZE = 100>
class CQueueArray
{
public:
	CQueueArray()
	{
		m_Size = 0;
		m_Head = 0;
		m_Tail = 0;
	}
	~CQueueArray()
	{
	}

private:
	//+1을 해 준 이유는 Head와 Tail이 만나는 빈공간
	//하나를 위해서이다.
	T	m_Array[SIZE + 1];
	int m_Size;
	int m_Head;
	int m_Tail;

public:
	//tail에 데이터를 추가
	void push(const T& Data)
	{

		//꼬리 위치를 계산.
		int Tail = (m_Tail + 1) % (SIZE + 1);

		//꽉 찼을때 예외처리
		if (Tail == m_Head)
		{
			return;
		}

		//꼬리 위치에 데이터 삽입
		m_Array[Tail] = Data;

		//새로운 꼬리 위치 등록
		m_Tail = Tail;

		//사이즈 증가
		++m_Size;
	}


	//값을 읽기
	T& front()
	{
		if (empty())
		{
			assert(false);
		}

		int Head = (m_Head + 1) % (SIZE + 1);
	
		//값을 반환
		return m_Array[Head];
	}


	//값을 꺼내고 데이터를 삭제하기
	//Head 인덱스는 비어있는 공간으로 취급하고,
	//실제 데이터는 그 뒤부터 존재하므로
	//먼저 Head 인덱스를 옮겨 주고 값을 불러와도 문제가 없다.
	void pop()
	{
		if (empty())
		{
			assert(false);
		}

		//헤더 위치를 구하고 변경
		m_Head = (m_Head + 1) % (SIZE + 1);

		--m_Size;
	}


	int size() const
	{
		return m_Size;
	}

	bool empty() const
	{
		return (0 == m_Size);
	}

	int Capacity() const
	{
		return SIZE;
	}

	//써클큐가 다 찼는지 확인용
	bool full()
	{
		return (m_Size == SIZE);
	}
};

 

 

 

 

//main.cpp

#include "QueueArray.h"

int main()
{
	std::cout << "\n===== 배열형 써클큐 확인 =====" << std::endl;
	CQueueArray<int> CQ;

	for (int i = 0; i < 10; ++i)
	{
		CQ.push(i);
		
	}

	while (!CQ.empty())
	{
		std::cout << CQ.front() << std::endl;
		CQ.pop();
	}

	std::cout << "남은 Size: " << CQ.size() << std::endl;
    
    return 0;
    
}