[ 자료 구조 ] 큐 (Queue)와 스택 (Stack)

Hanna·2024년 9월 6일
post-thumbnail

🗂 자료구조(Data Structure)란?

데이터를 효율적으로 저장하고 관리하는 방법을 의미합니다.
자료구조는 크게 선형구조와 비선형구조로 나뉘는데 각각의 구조는
데이터가 어떻게 저장되고 처리되는지에 따라 성능과 사용 목적이 달라집니다.


📊 선형 구조 (Linear Structure)

데이터가 일렬로 나열되어 있는 형태로, 
각 데이터 요소가 이전과 다음 요소와 직접적으로 연결되어 있습니다.
선형구조에서는 데이터의 순서가 매우 중요하며,
주로 순차적으로 접근하거나 처리해야 하는 경우에 사용됩니다.

>> 대표적인 선형 구조

  • 배열(Array): 고정된 크기의 연속된 메모리 공간에 데이터를 저장하는 구조.
  • 연결 리스트(Linked List): 각 데이터가 포인터로 다음 데이터와 연결되는 방식.
  • 큐(Queue): 선입선출(FIFO) 방식으로 데이터를 처리하는 자료구조.
  • 스택(Stack): 후입선출(LIFO) 방식으로 데이터를 처리하는 자료구조.

🌳 비선형 구조 (Non-linear Structure)

데이터들이 계층적이거나 네트워크 구조로 연결되어 있어,
각 데이터 간의 관계가 1:1이 아닌 1:다 또는 다:다로 연결됩니다. 
비선형구조에서는 특정 데이터와 그 주변 데이터 간의 관계가 중요하며, 
복잡한 데이터 구조를 효율적으로 표현하고 처리할 수 있습니다.

>> 대표적인 비선형 구조

  • 트리(Tree): 계층적 구조로, 루트 노드를 시작으로 각 노드가 부모-자식 관계를 가지며 여러 레벨로 나뉨
  • 그래프(Graph): 정점(Node)과 간선(Edge)으로 구성된 네트워크 구조로, 다양한 경로를 통해 데이터가 연결



🚶‍♂️🚶‍♀️ 큐 (Queue)

큐는 선입선출(FIFO, First In First Out) 원칙에 따라 데이터를 저장하고 처리하는 구조입니다.
즉, 먼저 들어온 데이터가 먼저 나가게 됩니다. 
큐는 일상 생활에서도 흔히 볼 수 있는 구조로, 식당에서 웨이팅을 기다릴때
빈자리가 생기면 표를 뽑은 순서대로 들어가게 되는 경우를 예를 들 수 있습니다.


큐의 동작 방식

  • 입구 (Enqueue): 데이터를 큐에 추가하는 과정이며, 큐의 맨 뒤에 데이터를 추가합니다.
  • 출구 (Dequeue): 큐에서 데이터를 제거하는 과정이며. 큐의 맨 앞에서 데이터를 제거합니다.

큐의 특징

  • 데이터를 입력한 순서대로 처리할 수 있도록 설계되어 있습니다.
  • FIFO 원칙에 따라, 큐의 앞쪽에서 데이터가 먼저 처리됩니다.
  • 응용 예: 프로세스 스케줄링, 버퍼 관리 등

예시코드


// 큐를 생성하고 초기 상태 선언
let queueData = [];


// 큐에 데이터를 추가하는 함수
const enqueue = (queue, data) => {
    // 큐의 맨 뒤에 데이터를 추가
    queue.push(data); 
};


// 큐에서 데이터를 제거하는 함수
const dequeue = (queue) => {
    // 큐가 비어있는 경우 에러 메시지를 반환
    if (queue.length === 0) {
        return { error: 'Queue is empty' };
    }
    // 큐의 맨 앞에서 데이터를 제거하고 반환
    return queue.shift();
};


// 큐의 첫 번째 데이터를 확인하는 함수
const frontQueueData = (queue) => {
    // 큐가 비어있는 경우 에러 메시지를 반환
    if (queue.length === 0) {
        return { error: 'Queue is empty' };
    }
    // 큐의 맨 앞 데이터를 반환
    return queue[0];
};


// 큐가 비어있는지 확인하는 함수
const isEmpty = (queue) => {
    // 큐의 길이가 0이면 true, 아니면 false를 반환
    return queue.length === 0;
};


// 큐의 크기를 확인하는 함수
const size = (queue) => {
    // 큐의 현재 길이를 반환
    return queue.length;
};


// 큐의 모든 데이터를 출력하는 함수
const printQueue = (queue) => {
    // 큐의 모든 데이터를 문자열로 변환하여 반환
    return queue.join(', ');
};


// 사용 예시
enqueue(queueData, 'A'); // 큐에 'A' 추가
enqueue(queueData, 'B'); // 큐에 'B' 추가
console.log(printQueue(queueData)); // A, B 출력
console.log(dequeue(queueData)); // A 출력 후 큐에서 제거
console.log(printQueue(queueData)); // B 출력
console.log(frontQueueData(queueData)); // B 출력 (큐의 첫 번째 데이터)
console.log(isEmpty(queueData)); // false 출력 (큐가 비어있지 않음)
console.log(size(queueData)); // 1 출력 (큐의 크기)


📚 스택 (Stack)

스택은 후입선출(LIFO, Last In First Out) 원칙에 따라 데이터를 저장하고 처리하는 구조입니다.
즉, 마지막에 들어온 데이터가 가장 먼저 나가게 됩니다.
박스에 책을 넣을때 가장 마지막에 넣은 책이 가장 먼저 나오는 것처럼
스택도 마지막에 들어온 데이터가 먼저 처리됩니다.


스택의 동작 방식

  • 푸시 (Push): 데이터를 스택에 추가하는 과정입니다. 스택의 맨 위에 데이터를 추가합니다.
  • 팝 (Pop): 스택에서 데이터를 제거하는 과정입니다. 스택의 맨 위에서 데이터를 제거합니다.

스택의 특징

  • 데이터가 들어온 순서와 반대로 처리됩니다.
  • LIFO 원칙에 따라, 스택의 위쪽에서 데이터가 먼저 처리됩니다.
  • 응용 예: 함수 호출 스택, 재귀 호출 등

예시코드


// 스택을 생성하고 초기 상태 선언
let stackData = [];


// 스택에 데이터를 추가하는 함수
const push = (stack, data) => {
    // 스택의 맨 위에 데이터를 추가
    stack.push(data); 
};


// 스택에서 데이터를 제거하는 함수
const pop = (stack) => {
    // 스택이 비어있는 경우 에러 메시지를 반환
    if (stack.length === 0) {
        return { error: "Stack is empty" };
    }
    // 스택의 맨 위에서 데이터를 제거하고 반환
    return stack.pop();
};


// 스택의 가장 위 데이터를 확인하는 함수
const peek = (stack) => {
    // 스택이 비어있는 경우 에러 메시지를 반환
    if (stack.length === 0) {
        return { error: "Stack is empty" };
    }
    // 스택의 맨 위 데이터를 반환
    return stack[stack.length - 1];
};


// 스택이 비어있는지 확인하는 함수
const isEmpty = (stack) => {
    // 스택의 길이가 0이면 true, 아니면 false를 반환
    return stack.length === 0;
};


// 스택의 크기를 확인하는 함수
const size = (stack) => {
    // 스택의 현재 길이를 반환합니다.
    return stack.length;
};


// 스택의 모든 데이터를 출력하는 함수
const printStack = (stack) => {
    // 스택의 모든 데이터를 문자열로 변환하여 반환
    return stack.join(', ');
};


// 스택 사용 예시
push(stackData, 10); // 스택에 10 추가
push(stackData, 20); // 스택에 20 추가
push(stackData, 30); // 스택에 30 추가
console.log('스택 출력:', printStack(stackData)); // 스택 출력: 10, 20, 30
console.log('스택 크기:', size(stackData)); // 스택 크기: 3
console.log('스택에서 pop한 값:', pop(stackData)); // 스택에서 pop한 값: 30
console.log('스택의 최상위 값:', peek(stackData)); // 스택의 최상위 값: 20
console.log('스택이 비었는지:', isEmpty(stackData)); // 스택이 비었는지: false
profile
A Developer Who Thinks Why

0개의 댓글