큐(Queue)란 양 쪽 끝에서만 데이터를 넣거나 뺄 수 있는 삽입과 삭제의 위치가 제한적인 형태의 선입선출(First-In-First-Out) 구조를 갖는 선형 자료구조이다.
자바 라이브러리의 큐 메서드에는 두가지 형태의 메서드가 있다,
첫째는 수행이 실패했을때Exception
을 발생시키는 메서드이고 둘째는 수행이 실패했을때null
또는false
를 반환하는 메서드이다.
boolean add(E item)
item
을 Queue
에 삽입true
를 반환, 삽입할 공간이 없는 경우는 예외발생(IllegalStatementException
)를 발생시킨다.E element()
Queue
의 Head
에 있는 item
을 삭제하지 않고 해당 item
을 반환한다.Queue
가 비어있으면 예외(NoSuchElementException
)를 발생시킨다.E remove()
Queue
의 Head
에 있는 item
을 삭제하고 해당 item
을 반환Queue
가 비어있으면 예외(NoSuchElementException
)를 발생시킨다.boolean offer(E item)
add(E)
와 동일한 기능true
를 반환하고 실패하면 false
를 반환한다.E peek()
element()
와 동일한 기능Queue
가 비어있으면 null
을 반환.E poll()
remove()
와 동일한 기능Queue
가 비어있으면 null
을 반환.선입선출 형식의 구조를 갖는다. 선입선출 형식 이란 아래 그림처럼 먼저 들어온 순서대로 나오는 방식을 말한다.
poll()
: 리스트의 첫 번째 항목을 제거한다.add(item)
: item 하나를 큐의 가장 끝 부분에 추가한다.peek()
: 큐의 가장 앞에 있는 항목을 반환한다.isEmpty()
: 큐가 비어 있을 때 true
를 반환한다.size()
: 큐에 들어있는 item의 개수를 반환한다.큐(Queue) 를 구현하는 방식에는 배열(Array) 을 이용해 구현하는 방식과 연결리스트(LinkedList) 를 이용해 구현하는 방식이있다.
따라서, 모든 원소의 값을 필요로 하거나 중간 데이터를 삽입삭제할 경우 연결리스트, 특정 데이터에 접근하는것이 목적이라면 배열을 사용하는것이 좋다.
연결리스트로 구현된 큐에서 데이터와 데이터의 위치를 저장하는 노드(Node) 객체는 아래 그림과 같다.
위 그림같은 노드들을 연결한 형식이 아래 그림과 같은 연결리스트(LinkedList) 가 된다.
큐에서 데이터를 추가하는 기능은 offer()
또는 add()
에 의해 이루어진다. 데이터를 추가하는 동작은 아래 그림처럼 이루어진다.
먼저, 데이터를 추가할 노드를 생성하고 큐의 제일 마지막 노드와 연결한 후에 tail
노드를 새로 추가된 노드로 변경해준다.
큐에서 데이터를 삭제하는 기능은 poll()
또는 remove()
에 의해 이루어진다. 데이터를 삭제하는 동작은 아래 그림처럼 이루어진다.
노드에 이어져있던 링크를 위 그림처럼 끊어버리는 방식으로 데이터를 삭제할 수 있다.
class Node <E>{
E data;
Node<E> next; // 다음 노드의 주소를 가리키는 변수
public Node(final E data) {
this.data = data;
this.next = null;
}
}
public class LinkedListQueue<E> {
private Node<E> head; // 큐에서 가장 처음 노드 객체를 가리키는 변수
private Node<E> tail; // 큐에서 가장 마지막 노드 객체를 가리키는 변수
private int size; // 큐에 담긴 요소의 개수
public LinkedListQueue() {
this.head = null;
this.tail = null;
this.size = 0;
}
public boolean offer(final E e) {
Node<E> newNode = new Node<>(e);
if(size == 0){
// 큐가 비어있을 경우
head = newNode;
}else{
// 비어있지 않을경우 마지막 노드(tail)이 다음 노드(next)를 가리키도록 한다.
tail.next = newNode;
}
tail = newNode;
size++;
return true;
}
public E poll() {
if (size == 0) {
// 삭제할 요소가 없다면 null 반환.
return null;
}
// 삭제될 요소의 데이터를 반환하기 위한 임시 변수
E element = head.data;
// head 노드의 다음노드
Node<E> nextNode = head.next;
head.data = null;
head.next = null;
// head 가 가리키는 노드를 삭제된 head 노드의 다음노드를 가리키도록 변경
head = nextNode;
size--;
return element;
}
public E peek() {
// 요소가 없을경우 null 반환
if(size == 0){
return null;
}
return head.data;
}
public E element() {
E element = peek();
if(element == null){
throw new NoSuchElementException();
}
return element;
}
public int size(){
return size;
}
public int isEmpty(){
return size == 0;
}
}
offer()
는 큐의 제일 뒤에 데이터를 추가한다.
큐가 비어있다면 새 요소는 head
이며 동시에 tail
이 된다. 그렇기 때문에 head
를 새 노드를 가리키도록 해야하고 그 외에는 tail
이 가리키는 요소의 다음 노드(tail.next
)를 새 노드를 가리키도록 한 뒤 tail
을 새 노드로 지정한다.
poll()
은 큐의 제일 앞에 데이터를 삭제하고 그 값을 반환한다.
만약, 큐가 비어있다면 null
을 반환한다. 만약 비어있지 않다면 큐의 새로운 head
는 삭제된 head
노드가 가리키던 다음노드(head.next
)로 변경한다.
버퍼는 데이터를 한곳에서 다른 한곳으로 전송하는 동안 일시적으로 데이터를 보관하는 메모리의 영역이며 일반적으로 입출력 및 네트워크 관련 기능에서 이용한다.
순서대로 입력/출력/전달 되어야 하므로 FIFO방식의 큐가 이용된다.
큐는 데이터가 입력된 순서대로 처리해야 할 필요가 있는 상황에 이용한다.
[Reference]
자바 - 연결리스트를 이용한 Queue 구현
자료구조-배열과 연결리스트의 장단점
포스트it의 개발자 도전기
Heee's Development Blog