데이터를 저장하고 관리하는 방법 중 선형 자료구조의 두가지
스택과 큐 에 대해서 알아보자.
- push() - 데이터 넣음
- pop() - 데이터 최상위 값 뺌
- isEmpty() - 비었는지 확인
- isFull() - 꽉 찼는지 확인
push와 pop을 할 때 해당 위치를 알고 있어야 하므로 스택 포인터(SP)가 필요
private int sp = -1; // SP 기본 값 -1
배열
push
public void push(Object o) { if(isFull(o)) { return; //스택 포인터가 최대 크기와 같으면 return } stack[++sp] = o; //아니면 스택의 최상위 위치에 값을 넣음 }
pop
public Object pop() { if(isEmpty(sp)) { return null; //스택 포인터가 0이 되면 null로 return; } Object o = stack[sp--]; //아니면 스택의 최상위 위치 값을 꺼내옴 return o; }
isEmpty
private boolean isEmpty(int cnt) { return sp == -1 ? true : false; //입력 값이 최초 값과 같다면 true, 아니면 false }
isFull
private boolean isFull(int cnt) { return sp + 1 == MAX_SIZE ? true : false; //스택 포인터 값+1이 MAX_SIZE와 같으면 true, 아니면 false }
동적 배열 스택
public void push(Object o) { if(isFull(sp)) { Object[] arr = new Object[MAX_SIZE * 2]; // 기존 스택의 2배 크기만큼 임시 배열 arr 생성 System.arraycopy(stack, 0, arr, 0, MAX_SIZE); // arraycopy로 stack의 인덱스 0부터 MAX_SIZE만큼 arr 배열의 0번째부터 복사 stack = arr; // arr 값을 stack에 저장 MAX_SIZE *= 2; // 2배로 증가 } stack[sp++] = o; }
enQueue() : 데이터 넣음
deQueue() : 데이터 뺌
isEmpty() : 비어있는 지 확인
isFull() : 꽉 찼는 지 확인
데이터를 넣고 뺄 때 해당 값의 위치를 기억해야 함(스택 포인터 역할)
이 위치를 기억하고 있는 게 front와 rear
front : deQueue(데이터를 뺄) 위치 기억
rear : enQueue(데이터를 넣을) 위치 기억
public boolean isFull() {
return (rear == queueSize-1);
}
// rear가 사이즈-1과 같아지면 가득찬 것
이를 개선한 것이
초기 front 와 rear는 맨 처음 인덱스(0)에 위치,
포화 상태를 쉽게 구분하기 위해 자리 하나를 항상 비워둠
(index + 1) % size로 순환시킨다
이를 개선한 것이
크기 제한x, 삽입, 삭제 편리
public void enqueue(E item) {
Node oldlast = tail; // 기존의 tail 임시 저장
tail = new Node; // 새로운 tail 생성
tail.item = item;
tail.next = null;
if(isEmpty()) head = tail; // 큐가 비어있으면 head와 tail 모두 같은 노드 가리킴
else oldlast.next = tail; // 비어있지 않으면 기존 tail의 next = 새로운 tail로 설정
}
public T dequeue() {
// 비어있으면
if(isEmpty()) {
tail = head;
return null;
}
// 비어있지 않으면
else {
T item = head.item; // 빼낼 현재 front 값 저장
head = head.next; // front를 다음 노드로 설정
return item;
}
}