: 마지막에 들어온 요소가 먼저 나가는 LIFO(Last In First Out) 자료구조
x5
스택의 기본적인 연산으로는 push와 pop이 있다.
스택의 상태를 확인하기 위해 추가적인 함수도 제공한다.
➡️ 스택 구조는 조회가 필요하지 않으므로, 데이터를 저장하고 검색하는 프로세스가 매우 빠르며, 최상위 블록에서 데이터를 저장하고 검색하면 된다는 장점이 있다.
const stack = [];
// Push
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack); // [1, 2, 3]
// Pop
stack.pop();
console.log(stack); // [1, 2]
// Get Top
console.log(stack[stack.length - 1]); // 2
...
: 먼저 들어온 요소가 먼저 나가는 FIFO(First In First Out) 자료구조
x1
x5
버퍼링(buffering)
대부분의 컴퓨터 장치에서 발생하는 이벤트는 불규칙적으로 발생한다. 이에 비해 발생한 이벤트를 처리하는 장치(CPU)는 일정한 처리 속도를 가진다.
➡️ 이때 CPU는 불규칙적으로 발생한 이벤트를 규칙적으로 처리하기 위해 버퍼(buffer)를 사용한다.
컴퓨터와 프린터 사이의 데이터(data) 통신을 정리하면,
class Queue {
constructor() {
this.queue = []; // 요소를 넣을 배열 변수
this.front = 0; // 각각 front와 rear를 나타내기 위한 index 변수
this.rear = 0;
}
}
// Enqueue
enqueue(value) {
this.rear++;
this.queue[rear] = value;
// rear index를 1 증가시키고, 값을 넣는다.
}
// Dequeue
dequeue() {
const value = this.queue[this.front];
delete this.queue[this.front];
this.front++;
return value;
// front index에 해당하는 값을 반환하고, front index를 1 증가시킨다.
}
// Peek
peek() {
return this.queue[this.front];
// front index에 해당하는 값을 반환한다.
}
// 큐의 길이 구하기
size() {
return this.rear - this.front;
// rear index에서 front index를 뺀다.
}
const queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
console.log(queue.dequeue()); // 1
queue.enqueue(4);
console.log(queue.size()); // 3
console.log(queue.peek()); // 2
큐를
shift()
로 구현하면 안되는 이유맨 앞의 요소를 삭제하기 위해
shift()
를 사용하는 것은 선형 시간O(n)
이 걸린다. 삭제되는 위치 이후의 요소들을 모두 앞으로 한 칸씩 당겨줘야 하기 때문이다.
같은 이유로 맨 앞에 요소를 추가하는unshift()
역시 선형 시간O(n)
이 걸린다.반면에, 맨 끝의 요소를 추가/삭제하는
pop()
,push()
는 상수 시간O(1)
만 소요된다.
// Node 클래스
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
// Queue 클래스
class Queue {
constructor() {
this.head = null; // 생성자에서는 head와 tail을 null로 지정한다.
this.tail = null;
this.size = 0;
}
// 요소를 추가하기 위한 enqueue 함수
enqueue(newValue) {
const newNode = new Node(newValue); // 값을 받아 새로운 노드를 생성한다.
if(this.head === null) { // head가 비어있는 경우, head와 tail에 생성한 노드를 넣어준다.
this.head = this.tail = newNode;
} else { // head가 비어있지 않은 경우,
this.tail.next = newNode; // 꼬리 부분에 next에 생성한 노드를 넣어준다.
this.tail = newNode; // 새로 추가된 노드가 꼬리가 되도록 설정해준다.
}
this.size++;
}
// 요소를 빼기 위한 dequeue 함수
dequeue() {
const value = this.head.value; // head의 값을 별도의 변수에 담아두고,
this.head = this.head.next; // 리스트에서 head를 제거한다.
this.size--;
return value; // 앞서 담아둔 head의 값을 반환한다.
}
// head의 값을 그대로 리턴하는 peek 함수
peek() {
return this.head.value;
}
}
: Front와 Rear가 이어져있는 큐
Circular Queue는 연결 리스트로 구현했을 때 이점이 없다.
...
❔ 학습 후 궁금한 점
- 연결리스트로 스택, 큐 구현하기