Java) Queue 사용법
- 쓸 때마다 자꾸 까먹어서 정리하는 자바의 큐!!
Queue란?
- 먼저 들어온 것이 먼저 나가는 선입선출(FIFO; First In First Out) 구조를 가진 자료구조이다.
-
기본적으로 배열을 활용해 만들 수 있는 자료구조이지만 배열처럼 랜덤 인덱스에 접근할 수는 없다. 맨 앞에 있는 데이터에만 접근해서 값을 읽을 수 있고 데이터의 삽입은 큐의 맨 뒤에서만 가능하다.
- 큐의 맨 뒤에 데이터를 삽입하는 것을
Enqueue
라 하고 - 큐의 맨 앞에서 데이터를 제거하는 것을
Dequeue
라 한다. - 하지만 각 언어별로 제공되는 메서드명은 조금씩 다르다.
Queue 선언
- 난
C++
로 프로그래밍을 시작해서 자바의 큐 선언법이 참 낯설었다. - 자바에서의 큐
Queue
는 인터페이스이기 때문에new Queue()
로는 만들 수가 없다. (이것이 자바로 코테를 보는 걸 좀 꺼리게 만들었고 오랫동안 C++을 고집한 이유가 되기도 했다.) - 그렇기 때문에 큐를 구현하고 있는 클래스를 이용해 객체를 생성해야 하는데, 이는
LinkedList
가 구현하고 있기 때문에 이걸 이용해서 생성한다.
import java.util.LinkedList;
import java.util.Queue;
- 큐를 사용하려면
LinkedList
와Queue
두 가지를 임포트 해 주어야 한다. - 하지만 보통 자동완성이 되지 않는 코테에서 이걸 일일이 외워서 쓰기엔 너무 귀찮고 헷갈린다… 그래서 코테에선
import java.util.*;
로 가는 것이 편하다. util
패키지에 어지간한 자료구조는 다 들어있기 때문에 임포트문에 대한 강박을 좀 덜 수 있다.
// 제네릭 사용시 뒤에는 생략 가능
Queue<Integer> q = new LinkedList<>();
Queue<String> strQ = new LinkedList<String>();
// 제네릭 미사용 - 데이터 안정성이 좀 떨어져서 제네릭 사용이 권장됨
Queue q2 = new LinkedList();
- 위의 예제와 같이 제네릭을 사용해서 선언할 수 있고 제네릭 없이 선언할 수도 있다.
- 하지만 최신 자바에서는 데이터 안정성 면에서 제네릭을 사용하는 것을 권장하기 때문에 제네릭으로 데이터 타입을 명시해 주는 것이 좋다.
- 제네릭 사용시,
int
와 같은 Primitive 타입이 아니라Integer
와 같은 Wrapper 클래스를 써 주어야 한다. 왜냐면 저기엔 오브젝트를 넣기로 약속되어 있으니까.
Enqueue
q.add(1); // 큐에 1 삽입
q.offer(2); // 큐에 2 삽입
- 자바에서 큐에 데이터를 삽입하려면
add(value)
혹은offer(value)
를 사용하면 되는데 난offer()
를 많이 쓰는 편이다.
Dequeue
q.poll();
int i = q.poll();
Integer j = q.poll(); // 맨 앞 원소 반환하고 제거 - 비어있으면 null 반환
q.remove(); // 맨 앞 원소 제거 - 비어있으면 null exception 발생
- 큐의 맨 앞에 있는 데이터를 꺼내려면
poll()
또는remove()
메서드를 사용하면 되는데 두 개가 존재하는 이유는 리턴 타입이 다르기 때문이다. poll()
은 원소를 반환하고 제거하기 때문에 그냥 쓸 수도 있지만 반환값을 변수에 저장할 수도 있다. 큐가 비어있다면 null을 반환하기 때문에 큐에 저장된 데이터가 정수형과 같은 Primitive 타입이라면 Wrapper 클래스로 받는 것이 더 안정적일 것 같지만, 보통은 큐가 비어있는지 먼저 확인한 다음 값을 꺼내니까 편한걸로 써도 상관없을 거 같다.remove()
는 그냥 제거만 하기 때문에 큐가 비어있으면 예외가 발생한다.
Queue가 비었는지 확인하기
- 그래서 큐에서 값을 꺼내기 전에 큐가 비었는지 아닌지 먼저 확인한 다음 동작을 수행하는 것이 좋다.
if (!q.isEmpty()) {
q.poll();
... 블라블라
}
- 위와 같이 큐가 비었는지 확인한 다음 값을 꺼내는 연산을 하는 것이 안전하다.
isEmpty()
는 대부분의 컬렉션에서 사용할 수 있는 메서드로,boolean
타입으로 해당 자료구조가 비었는지 아닌지를 리턴해 준다.
Queue의 첫 번째 값 참조
int i = q.peek();
-
큐의 첫 번째 값을 제거하지 않고 그냥 확인만 하고 싶다면
peek()
메서드를 사용할 수 있다. -
자바에서 큐는 이 정도만 알면 충분히 응용할 수 있을 것 같다.