에르노트
스택 & 큐 with Javascript 본문
스택(Stack)
스택은 마지막에 삽입된 항목만 제거할 수 있는 자료구조이다. 그래서 후입선출, Last In First Out(LIFO) 방식의 자료구조라고 일컬어진다.
그리고 자바스크립트 배열은 이러한 스택의 특성을 그대로 살린 push()와 pop() 메소드를 제공한다. 따라서 자바스크립트 배열을 이용하면 손쉽게 스택을 구현할 수 있다.
생성
class Stack{
constructor(arr){
this.arr = []
if(arr) this.arr = arr
}
}
우선 Stack 클래스 내부에 멤버 변수로 배열을 하나 넣어준다.
삽입
push(val){
this.arr.push(val)
}
그리고 배열의 push() 메소드를 이용하여 스택의 push()를 구현한다.
삭제
pop(){
return this.arr.pop()
}
마찬가지로 pop()을 정의할 수 있다. 이때 pop()은 push()와 다르게 제거한 값을 반환한다는 점에 유의하자.
접근
top(){
return this.arr[this.arr.length-1]
}
스택의 개념에 맞게 top()메소드는 가장 마지막에 삽입된 요소를 반환하도록 구현해준다. 여기까지하면 스택이라 불리기에 손색이 없다.
그런데 자료구조로서 의미를 더하려면 조금 더 자유롭게 접근하고 검색할 수 있어햐 한다. 따라서 위에서부터 n번째 요소에 접근하는 메소드와 특정 요소의 존재 여부를 검색하는 메소드를 생각해 볼 수 있다.
복사
copy(){
return this.arr.slice()
}
접근과 검색을 할 때에 원본 배열을 건드리면 곤란하므로 copy() 메소드를 만들어준다.
n번째 요소 접근
function getStackNthTop(stack, n){
if(n <=0) throw 'error'
var copy = new Stack(stack.copy())
while(--n != 0) copy.pop()
return copy.pop()
}
간단하다. pop()을 n번 수행하면 n번째 요소에 접근할 수 있다. pop()의 시간복잡도는 O(1)이므로 n번째 요소에 접근하는 시간복잡도는 O(n)이다.
검색
function search(stack, element){
var copy = new Stack(stack.copy())
while(!copy.isEmpty()){
if(element == copy.pop()) return true
}
return false
}
일종의 완전 탐색이다. 전체 요소를 돌면서 pop()을 수행하고 검색하려는 요소와 맞아떨어지면 true 반환한다. 역시 n개 요소를 돌기 때문에 시간복잡도는 O(n)이다.
전체 소스(테스트 코드)
class Stack{
constructor(arr){
this.arr = []
if(arr) this.arr = arr
}
isEmpty(){
return this.arr.length == 0
}
copy(){
return this.arr.slice()
}
push(val){
this.arr.push(val)
}
pop(){
return this.arr.pop()
}
top(){
return this.arr[this.arr.length-1]
}
}
function getStackNthTop(stack, n){
if(n <=0) throw 'error'
var copy = new Stack(stack.copy())
while(--n != 0) copy.pop()
return copy.pop()
}
function search(stack, element){
var copy = new Stack(stack.copy())
while(!copy.isEmpty()){
if(element == copy.pop()) return true
}
return false
}
function test(){
var stack = new Stack()
console.log(stack)
//stack: empty
for(var i=1; i<=5; i++)
stack.push(i)
console.log(stack)
//stack: [1,2,3,4,5]
stack.pop()
console.log(stack)
//stack: [1,2,3,4]
console.log("top: " + stack.top())
//top: 4
console.log("2nd top: " + getStackNthTop(stack, 2))
//2nd top: 3
console.log("seacrh 1: " + search(stack, 1)) //true
console.log("seacrh 5: " + search(stack, 5)) //false
}
test()
큐(Queue)
큐는 스택과 반대로 가장 먼저 삽입된 항목만 제거할 수 있는 자료구조이다. 따라서 선입선출, First In First Out(FIFO) 방식의 자료구조라고 일컬어진다.
자바스크립트 배열은 큐의 특성을 살린 shift() 메소드 역시 포함하고 있다. 따라서 앞선 스택의 구현과 거의 비슷한 느낌으로 진행할 수 있다. 실제로 스택의 pop(), top()을 큐에서는 dequeue(), front()로서 다른 방향에서 접근할 뿐이다.
생성
class Queue{
constructor(arr){
this.arr = []
if(arr) this.arr = arr
}
}
삽입
enqueue(val){
this.arr.push(val)
}
삭제
dequeue(){
return this.arr.shift()
}
Javascript Array의 shift() 메소드에는 0번째 인덱스를 제거와 더불어 나머지 요소들의 인덱스 변경까지 포함되어 있다. 따라서 배열을 이용한 큐에서 요소 삭제의 시간복잡도는 O(n)이다.
접근
front(){
return this.arr[0]
}
n번째 요소 접근
function getQueueNthFront(queue, n){
if(n <=0) throw 'error'
var copy = new Queue(queue.copy())
while(--n != 0) copy.dequeue()
return copy.dequeue()
}
검색
function search(queue, element){
var copy = new Queue(queue.copy())
while(!copy.isEmpty()){
if(element == copy.dequeue()) return true
}
return false
}
전체 소스(테스트 코드)
class Queue{
constructor(arr){
this.arr = []
if(arr) this.arr = arr
}
isEmpty(){
return this.arr.length == 0
}
copy(){
return this.arr.slice()
}
enqueue(val){
this.arr.push(val)
}
dequeue(){
return this.arr.shift()
}
front(){
return this.arr[0]
}
}
function getQueueNthFront(queue, n){
if(n <=0) throw 'error'
var copy = new Queue(queue.copy())
while(--n != 0) copy.dequeue()
return copy.dequeue()
}
function search(queue, element){
var copy = new Queue(queue.copy())
while(!copy.isEmpty()){
if(element == copy.dequeue()) return true
}
return false
}
function test(){
var queue = new Queue([1,2,3,4,5])
console.log(queue) //queue: [1,2,3,4,5]
queue.dequeue()
console.log(queue) //queue: [2,3,4,5]
queue.enqueue(6)
console.log(queue) //queue: [2,3,4,5,6]
console.log("2nd front: " + getQueueNthFront(queue, 2)) //2nd front: 3
console.log("search 2: " + search(queue, 2)) //true
console.log("search 7: " + search(queue, 7)) //false
}
test()
정리
기본적으로 스택과 큐 모두 삽입, 삭제, 접근을 O(1)시간에 수행할 수 있다. 다만 위에서는 인덱스를 갖는 배열을 이용해서 큐의 dequeue() 메소드를 구현했기 때문에 이 경우의 시간복잡도는 O(n)이었다. 인덱스가 없는 연결 리스트(Linked List)를 이용해서 큐를 구현할 경우 O(1) 시간만에 가능하다. 또한 스택과 큐 모두 n번째 요소 접근과 검색을 O(n) 시간에 수행할 수 있다.
시간복잡도 | 삽입 | 삭제 | 접근 | n번째 접근 | 검색 |
스택 | O(1) | O(1) | O(1) | O(n) | O(n) |
큐 | O(1) | O(n) * |
O(1) | O(n) | O(n) |
'CS > Algorithm' 카테고리의 다른 글
이중 연결 리스트 with Javascript (0) | 2020.09.27 |
---|---|
연결 리스트 with Javascript (0) | 2020.09.24 |