스택은 LIFO(Last In First Out) 원칙을 따르는 선형 자료구조다. 마지막에 삽입된 요소가 가장 먼저 삭제되는 구조로, 한쪽 끝(top)에서만 삽입과 삭제가 이루어진다.
↓ push ↑ pop
┌─────────┐
│ 5 │ ← top (최상단)
├─────────┤
│ 3 │
├─────────┤
│ 1 │
└─────────┘
연산 | 시간 복잡도 | 설명 |
---|---|---|
push | O(1) | 최상단에 삽입 |
pop | O(1) | 최상단에서 제거 |
peek | O(1) | 최상단 요소 조회 |
search | O(n) | 특정 요소 찾기 |
자바스크립트에서 스택을 배열로 구현하면 본질적으로 배열과 동일하다고 생각할 수 있는데 여기서 중요한 점은 스택의 ADT(Abstract Data Type) 관점에서 생각해야 한다는 것이다.
스택에서 특정 요소를 찾으려면:
// 스택에서 요소 찾기 (이론적 구현)
function searchStack(stack, target) {
let temp = [];
let found = false;
// 스택을 하나씩 pop하면서 찾기
while (!stack.isEmpty()) {
let element = stack.pop();
temp.push(element);
if (element === target) {
found = true;
break;
}
}
// 원래 스택 상태로 복원
while (temp.length > 0) {
stack.push(temp.pop());
}
return found;
}
class ArrayStack<T> {
private items: T[] = [];
// 요소 삽입
push(item: T): void {
this.items.push(item);
}
// 요소 제거 및 반환
pop(): T | undefined {
return this.items.pop();
}
// 최상단 요소 조회
peek(): T | undefined {
return this.items[this.items.length - 1];
}
// 스택이 비어있는지 확인
isEmpty(): boolean {
return this.items.length === 0;
}
// 스택 크기
size(): number {
return this.items.length;
}
// 스택 초기화
clear(): void {
this.items = [];
}
}
class StackNode<T> {
data: T;
next: StackNode<T> | null;
constructor(data: T) {
this.data = data;
this.next = null;
}
}
class LinkedStack<T> {
private top: StackNode<T> | null = null;
private count: number = 0;
push(data: T): void {
const newNode = new StackNode(data);
newNode.next = this.top;
this.top = newNode;
this.count++;
}
pop(): T | undefined {
if (!this.top) {
return undefined;
}
const data = this.top.data;
this.top = this.top.next;
this.count--;
return data;
}
peek(): T | undefined {
return this.top?.data;
}
isEmpty(): boolean {
return this.top === null;
}
size(): number {
return this.count;
}
}
interface Modal {
id: string;
component: React.ComponentType;
props?: Record<string, any>;
}
const ModalProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [modalStack, setModalStack] = useState<Modal[]>([]);
const openModal = (modal: Modal) => {
setModalStack(prev => [...prev, modal]);
};
const closeModal = () => {
setModalStack(prev => prev.slice(0, -1)); // pop과 같은 효과
};
const closeAllModals = () => {
setModalStack([]);
};
return (
<ModalContext.Provider value={{ openModal, closeModal, closeAllModals }}>
{children}
{modalStack.map((modal, index) => (
<modal.component key={modal.id} {...modal.props} />
))}
</ModalContext.Provider>
);
};