Chapter1. 자료구조
Chapter2. Stack과 Queue
2-1 Stack
2-2 Queue
2-3 원형 큐(Circular Queue)
자료구조 : 컴퓨터 과학에서 효율적인 접근 및 수정을 가능케 하는 자료의 조직, 관리, 저장을 뜻함
자료구조를 많이 아는 개발자 = 데이터를 체계적으로 저장, 효율적으로 활용할 줄 아는 개발자 = 알고리즘 로직을 잘 짜는 개발자
Stack : 쌓다, 쌓이다, 포개지다
데이터를 순서대로 쌓는 자료구조
프링글스
가장 먼저 들어간 감자칩이 가장 나중에 나온다.
- 프링글스 통 : 자료구조 Stack
- 감자칩 : 데이터(data)
입력과 출력이 하나의 방향으로 이뤄지는 제한적 접근 구조
1. LIFO(Last In First Out) & FILO(First In Last Out) : 먼저 들어간 데이터는 제일 나중에 나오는 후입선출의 구조
push
pop
예1) 1, 2, 3, 4를 스택에 차례대로 넣는다.
stack.push(데이터)
---------------------------
1 <- 2 <- 3 <- 4
---------------------------
1번이 제일 먼저, 4번이 마지막으로 들어가게 된다.
예2) 스택이 빌 때까지 데이터를 전부 빼낸다.
stack.pop()
---------------------------
---------------------------
4, 3, 2, 1
제일 마지막에 있는 데이터부터 차례대로 나온다.
2. 저장되는 데이터는 유한하고 정적이어야 한다.
ex. 콜 스택(Call Stack) : 콜 스택 내부에 함수 실행 데이터는 스택의 프레임(해당 기능에 필요한 데이터가 저장되는 공간)으로 저장되며, 함수가 새로운 변수를 선언하면 스택의 최상위 블록으로 push되는 구조다. 즉, 함수가 종료될 때마다 최상위 블록이 지워지는 후입선출 구조이므로 여기에 저장된 데이터는 정적 특성을 가져야지만이 컴파일 시간이 결정된다.
3. 스택의 크기는 제한되어 있다.
class Stack {
//stack constructor를 생성
constructor() {
this.storage = {};
this.top = 0;
}
// stack의 사이즈 구하기
// this.top은 스택이 쌓일 때마다 하나씩 증가하기 때문에 top으로 size를 구할 수 있다.
// this.top : 스택에 새롭게 추가될 요소의 인덱스. 0부터 1씩 증감하며 표현하기 때문에 전체 요소의 개수를 나타낼 수 있다
size() {
return this.top;
}
//stack에 element를 추가
//새롭게 추가될 요소의 인덱스를 나타내는 this.top을 키로, 요소를 값으로 하여 storage에 할당한다. this.top은 다음 인덱스를 가리키게 하여 새로운 요소에 대비합니다.
push(element) {
this.storage[this.top] = element;
this.top += 1;
}
// stack에서 element를 제거한 뒤 해당 element를 반환
// 만약 size가 0이라면 아무 일도 일어나지 않음
// top-1로 최상단을 설정한 후 변수에 저장하고, 스택에서 삭제
// 하나를 제거했으니 top도 감소한다.
pop() {
if (this.size() <= 0) {
return;
}
const result = this.storage[this.top - 1];
delete this.storage[this.top - 1];
this.top -= 1;
return result;
}
}
Queue : 줄을 서서 기다리다, 대기행렬
고속도로의 톨게이트 : 자동차가 진입한 순서대로 통행료를 내고 톨게이트를 통과한다.
- 톨게이트 : Queue 자료구조
- 자동차 : 데이터
자료구조 Queue는 데이터(data)가 입력된 순서대로 처리할 때 주로 사용한다.
입력과 출력의 방향이 고정되어 있으며, 두 곳으로 접근이 가능하다
1. FIFO(First In First Out) & LILO(Last In Last Out) : 먼저 들어간 데이터(data)가 먼저 나오는 선입선출 구조
enqueue
dequeue
예1) 1, 2, 3, 4를 큐에 차례대로 넣는다.
queue.enqueue(데이터)
출력 방향 <---------------------------< 입력 방향
1 <- 2 <- 3 <- 4
<---------------------------<
들어간 순서대로, 1번이 제일 먼저 들어가고 4번이 마지막으로 들어간다.
예2) 큐가 빌 때까지 데이터를 전부 빼낸다.
queue.dequeue(데이터)
출력 방향 <---------------------------< 입력 방향
<---------------------------<
1, 2, 3, 4
제일 첫 번째 있는 데이터부터 차례대로 나온다.
2. 데이터는 하나씩 넣고 뺄 수 있다.
3. 두 개의 입출력 방향을 가진다.
큐는 주로 데이터가 입력된 시간 순서대로 처리해야할 때 사용함
각 장치 사이에 존재하는 속도, 시간차이를 극복하기 위해 임시 기억 장치의 자료구조로 Queue를 사용한다. 이것을 통틀어 버퍼(buffer)라고 한다.
그 외 : 은행업무, 콜센터 고객 대기시간, 프로세스 관리, BFS 알고리즘, 캐시(Cache) 구현
용어 | 설명 |
---|---|
getBuffer() | 데이터 전체 반환 |
enQueue() | 데이터 추가 rear + 1 |
deQueue() | 데이터 삭제 front + 1 |
front() | 첫 번째 데이터 조회 |
isFull() | Queue가 Full 상태인지를 확인 rear = n-1 rear 값이 마지막 데이터값을 나타내면 Full 상태이다. |
isEmpty() | Queue가 empty 상태인지를 확인 front = rear : 데이터가 없다는 뜻 |
dataSize() | Queue 안의 데이터 개수 확인 |
clear() | Queue 초기화 |
class Queue {
//가장 앞에 있는 요소를 front,
//가장 뒤에 있는 요소를 rear.
constructor() { //queue constructor 생성
this.storage = {};
this.front = 0;
this.rear = 0;
}
// queue의 사이즈를 구하기
// queue는 추가될 때, rear의 값이 커지고 삭제 될 때, front가 변경이 때문에, 각 값을 알아야 size를 구할 수 있음.
size() {
return this.rear - this.front;
}
// queue에 element를 추가
// 새롭게 추가될 요소의 인덱스를 나타내는 this.rear를 키로, 요소를 값으로 하여 storage에 할당
// this.rear : 다음 인덱스를 가리키게 하여 새로운 요소에 대비
enqueue(element) {
this.storage[this.rear] = element;
this.rear += 1;
}
// queue에서 element를 제거 -> 해당 element를 반환
// 만약 size가 0 : 아무 일 X
// this.front+1로 가장 앞에 있는 요소를 다시 설정한 후 변수에 저장하고, 큐에서 삭제한다.
dequeue() {
if (this.size() === 0) {
return;
}
const result = this.storage[this.front];
delete this.storage[this.front];
this.front += 1;
return result;
}
}
- 탄생 배경
- Queue 구조 : 데이터를 넣는 위치(rear)와 데이터를 가져오는 위치(front)가 다르다. 이를 반복하다보면 데이터를 넣을 수 없는 상태가 발생한다.
→ 이러한 문제점을 해결한 것이 원형 큐
원형 큐 : 데이터를 넣고 가져오는 방향이 없는 구조
셀 병합 어떻게 ... ?
자료구조 | 삽입 연산 | 삭제 연산 | ||
---|---|---|---|---|
연산자 | 삽입위치 | 연산자 | 삭제 위치 | |
스택 | push | top | pop | top |
큐 | enQueue | rear | deQueue | front |