https://leetcode.com/problems/design-circular-queue/description/
- 원형 큐를 디자인하라, 큐가 비어 있다면 -1을 리턴하며, 해당 원형 큐의 사용 예는 다음과 같다.
풀이 1) 배열을 이용한 풀이
- 원형큐(Circular Queue)는 FIFO 구조를 지닌다는 점에서 기존 큐와 동일하다.
- 그러나 마지막 위치가 시작 위치와 연결되는 원형 구조를 띠기 때문에, 링 버퍼(Ring Buffer)라고 부른다.
- 기존의 큐는 공간이 꽉 차면 더 이상 엘리먼트를 추가할 수 없다.
- 심지어 앞쪽에 엘리먼트들이 deQueue()로 모두 빠져서 충분한 공간이 남게 돼도 그 쪽으로는 추가할 수 있는 방법이 없다.
- 그러나 원형 큐는 앞쪽에 공간이 남아 있다면 동그랗게 연결해 앞쪽으로 추가할 수 있도록 재활용이 가능하다.
- 동작원리는 투 포인터와도 비슷하다.
- 마지막 위치와 시작 위치를 연결하는 원형 구조를 만들고, 엘리먼트의 시작점과 끝점을 따라 투 포인터가 움직인다.
- enQueue()를 하게 되면 rear 포인터가 앞으로 이동하고, deQueue()를 하게 되면 front 포인터가 앞으로 이동한다.
- 이렇게 enQueue()와 deQueue()를 반복하게 되면 서로 동그랗게 연결되어 있기 때문에 투 포인터가 빙글빙글 돌면서 이동하는 구조가 된다.
- 만약 front 포인터와 rear 포인터가 같은 위치에서 서로 만나게 되면 그때는 여유 공간이 하나도 없다는 뜻이므로 공간 부족 에러를 발생시킨다.
- 배열로 원형 큐 구현
1) 초기화
int q[];
int front =0, rear = -1, len = 0;
public MyCircularQueue(int k) {
//k 크기의 원형 큐로 사용할 배열 선언
this.q = new int[k];
}
- 큐의 크기 k를 입력값으로 받아 front 포인터는 0, rear 포인터는 한 칸 더 뒤인 -1에서 시작한다.
2) enQueue
public boolean enQueue(int value) {
//꽉 차 있지 않다면 삽입 진행
if(!this.isFull())
{
//rear 포인터 한 칸 앞으로 이동, 최대 크기를 초과하면 나머지 위치로 이동
this.rear = (this.rear+1)%this.q.length;
//rear 위치에 값 삽입
this.q[rear] = value;
//현재 큐의 크기 계산
this.len++;
return true;
}
else
{
return false;
}
- rear 포인터를 한 칸 앞으로 이동하고 해당 위치에 값을 넣는다.
- 초깃값을 -1로 지정했기 때문에 맨 처음에는 인덱스 0에 현재 값을 넣게 된다.
- 전체 길이만큼 모듈로 연산을 하여 포인터의 위치가 전체 길이를 벗어나지 않게 한다.
3) deQueue
public boolean deQueue() {
//텅 비어 있지 않다면 삭제 진행
if(!this.isEmpty())
{
//front 포인터 한 칸 앞으로 이동, 최대 크기를 초과하면 나머지 위치로 이동
this.front = (this.front+1)%this.q.length;
//현재 큐의 크기 계산
this.len--;
return true;
}
else
{
return false;
}
}
- 먼저 !this.isEmpty()로 비어 있지 않은지 학인하고 front 포인터를 한 칸 앞으로 이동한다.
- 마찬가지로 모듈로 연산으로 최대 길이를 넘지 않도록 한다.
- 현재 큐의 크기를 하나 줄인다.
- 이렇게 하면 기존의 값은 남아 있으나 이미 포인터는 한 칸 앞으로 이동한 상태이기 때문에 그 값은 더 이상 쓰이지 않는다.
- 나중에 rear 포인터가 한 바퀴 돌아서 그 위치를 가리키고, 새로운 값이 들어오면 자연스럽게 업데이트 될 것이다.
class MyCircularQueue {
int q[];
int front =0, rear = -1, len = 0;
public MyCircularQueue(int k) {
//k 크기의 원형 큐로 사용할 배열 선언
this.q = new int[k];
}
public boolean enQueue(int value) {
//꽉 차 있지 않다면 삽입 진행
if(!this.isFull())
{
//rear 포인터 한 칸 앞으로 이동, 최대 크기를 초과하면 나머지 위치로 이동
this.rear = (this.rear+1)%this.q.length;
//rear 위치에 값 삽입
this.q[rear] = value;
//현재 큐의 크기 계산
this.len++;
return true;
}
else
{
return false;
}
}
public boolean deQueue() {
//텅 비어 있지 않다면 삭제 진행
if(!this.isEmpty())
{
//front 포인터 한 칸 앞으로 이동, 최대 크기를 초과하면 나머지 위치로 이동
this.front = (this.front+1)%this.q.length;
//현재 큐의 크기 계산
this.len--;
return true;
}
else
{
return false;
}
}
public int Front() {
//맨 앞의 값을 가져온다.
return (this.isEmpty())?-1 : this.q[this.front];
}
public int Rear() {
//맨 뒤의 값을 가져온다.
return (this.isEmpty())?-1:this.q[this.rear];
}
public boolean isEmpty() {
//현재 큐의 크기가 0이면 비어 있음
return this.len == 0;
}
public boolean isFull() {
//현재 큐의 크기가 전체 큐의 크기와 일치하면 꽉 차 있음
return this.len == this.q.length;
}
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue obj = new MyCircularQueue(k);
* boolean param_1 = obj.enQueue(value);
* boolean param_2 = obj.deQueue();
* int param_3 = obj.Front();
* int param_4 = obj.Rear();
* boolean param_5 = obj.isEmpty();
* boolean param_6 = obj.isFull();
*/
4 밀리초
'Java > 알고리즘' 카테고리의 다른 글
[자바 알고리즘 인터뷰] 10장 데크, 우선순위 큐 (2) k개 정렬 리스트 병합 (0) | 2024.05.10 |
---|---|
[자바 알고리즘 인터뷰] 10장 데크, 우선순위 큐 (1) 원형 데크 디자인 (0) | 2024.05.10 |
[자바 알고리즘 인터뷰] 9장 큐,스택 (5) 스택을 이용한 큐 구현 (0) | 2024.05.10 |
[자바 알고리즘 인터뷰] 9장 스택,큐 (4) 큐를 이용한 스택 구현 (0) | 2024.05.10 |
[자바 알고리즘 인터뷰] 9장 스택, 큐 (3) 일일 온도 (0) | 2024.05.10 |