[로봇활용_11주차] C# 컬렉션 심화: Queue<T>, Stack<T>, Dictionary<TKey, TValue>

최윤호·2025년 10월 18일
post-thumbnail

컬렉션(Collection) 심화

지난 글에서 우리는 순서가 있는 데이터 묶음의 표준, List<T>에 대해 알아봤습니다.
List<T>는 정말 다재다능해서 대부분의 상황에서 유용하게 쓰이죠.
때로는 데이터에 '규칙'을 부여하고 싶을 때가 있습니다.
이번 글에서는 데이터의 저장 순서나 접근 방식이 특별한 제네릭 컬렉션을 살펴보겠습니다.

1)Queue - 줄 서기

큐(Queue)는 이름 그대로 '대기열'을 흉내 낸 컬렉션입니다.
먼저 들어간 데이터가 먼저 나온다는 선입선출(FIFO: First-In, First-Out) 원칙을 따릅니다.

비유: 놀이공원 매표소

가장 먼저 줄을 선 사람이 가장 먼저 표를 삽니다.
중간에 끼어들거나 뒤에 있는 사람이 먼저 처리될 수 없죠.

Queue 사용법

  • Enqueue(item): 큐의 맨 뒤에 데이터를 추가합니다. (줄의 맨 끝에 서기)
  • Dequeue(): 큐의 맨 앞에서 데이터를 꺼내고 제거합니다.
    (내 순서가 되어 처리 받고 줄에서 빠져나오기)
  • Peek(): 큐의 맨 앞에 있는 데이터를 제거하지 않고 확인만 합니다.
    (다음 순서가 누군지 훔쳐보기)

[코드]

using System;
using System.Collections.Generic; // Queue<T>를 사용하려면 필요합니다.

// 상황: 은행 창구 대기열
Queue<string> waitingQueue = new Queue<string>();

// 1. 대기열에 손님들이 도착 (Enqueue)
waitingQueue.Enqueue("박철수");
waitingQueue.Enqueue("이민수");
waitingQueue.Enqueue("김유리");

Console.WriteLine($"다음 손님은 '{waitingQueue.Peek()}' 입니다.");

// 2. 창구에서 손님 처리 (Dequeue)
while (waitingQueue.Count > 0)
{
    string currentCustomer = waitingQueue.Dequeue();
    Console.WriteLine($"'{currentCustomer}' 손님, 업무를 처리합니다.");
}

Console.WriteLine($"남은 대기 인원: {waitingQueue.Count}명");

[실행 결과]

다음 손님은 '박철수' 입니다.
'박철수' 손님, 업무를 처리합니다.
'이민수' 손님, 업무를 처리합니다.
'김유리' 손님, 업무를 처리합니다.
남은 대기 인원: 0명

2)Stack - 접시 쌓기

스택(Stack)은 큐와 정반대의 개념입니다. 가장 나중에 들어간 데이터가
가장 먼저 나온다는 후입선출(LIFO: Last-In, First-Out) 원칙을 따릅니다.

비유: 식당에서 접시 사용

식당에서 갓 씻은 접시를 쌓아두는 것을 상상해 보세요.
우리는 항상 맨 위에 있는 접시, 즉 가장 마지막에 쌓아 올린 접시부터 사용합니다.
맨 아래에 있는 접시를 꺼내려면 위의 접시를 모두 치워야 하죠.

Stack 사용법

  • Push(item): 스택의 맨 위(Top)에 데이터를 추가합니다. (접시를 맨 위에 쌓기)
  • Pop(): 스택의 맨 위에서 데이터를 꺼내고 제거합니다. (맨 위 접시를 가져가기)
  • Peek(): 스택의 맨 위에 있는 데이터를 제거하지 않고 확인만 합니다.
    (맨 위 접시가 무엇인지 훔쳐보기)

[코드]

using System;
using System.Collections.Generic; // Stack<T>를 사용하려면 필요합니다.

// 상황: 웹 브라우저 '뒤로 가기' 기능
Stack<string> browserHistory = new Stack<string>();

// 1. 사용자가 페이지를 탐색 (Push)
browserHistory.Push("google.com");
browserHistory.Push("velog.io");
browserHistory.Push("github.com"); // 현재 페이지

Console.WriteLine($"현재 페이지: {browserHistory.Peek()}");

// 2. '뒤로 가기' 버튼 클릭 (Pop)
Console.WriteLine("\n--- '뒤로 가기' 시작! ---");
while (browserHistory.Count > 0)
{
    string previousPage = browserHistory.Pop();
    Console.WriteLine($"'{previousPage}' 페이지에서 뒤로 갑니다.");
    if (browserHistory.Count > 0)
    {
        Console.WriteLine($" -> 현재 페이지: {browserHistory.Peek()}");
    }
    else
    {
        Console.WriteLine(" -> 초기 페이지로 이동합니다.");
    }
}

[실행 결과]

현재 페이지: github.com

--- '뒤로 가기' 시작! ---
'github.com' 페이지에서 뒤로 갑니다.
 -> 현재 페이지: velog.io
'velog.io' 페이지에서 뒤로 갑니다.
 -> 현재 페이지: google.com
'google.com' 페이지에서 뒤로 갑니다.
 -> 초기 페이지로 이동합니다.

3)Dictionary - 빠른 탐색의 왕

딕셔너리(Dictionary)는 데이터를 '키(Key)''값(Value)'으로 묶어 저장하는 컬렉션입니다.
고유한 '키(Key)'를 통해 '값(Value)'을 매우 빠른 속도로 찾아올 수 있습니다.
내부적으로 해시 테이블(Hash Table) 구조를 사용하여, 데이터의 양과 상관없이
평균 O(1)의 시간 복잡도(매우 빠른 속도)로 값을 찾을 수 있습니다.

비유: 영어 사전

우리는 'apple'이라는 단어(Key)를 찾고 '사과'라는 뜻(Value)을 바로 찾아냅니다.
사전의 첫 페이지부터 한 장씩 넘겨보지 않습니다.
딕셔너리(Dictionary)는 이처럼 매우 빠른 탐색 속도를 자랑합니다.

Dictionary 사용법

키(Key)는 반드시 고유해야 합니다.

  • Add(key, value): 새로운 키-값 쌍을 추가합니다.
  • 딕셔너리[key]: 키를 이용해 값을 읽거나 수정합니다. (배열의 인덱스처럼 사용)
  • ContainsKey(key): 특정 키가 존재하는지 안전하게 확인할 수 있습니다.
  • Remove(key): 키를 이용해 해당 키-값 쌍을 제거합니다.

[코드]

using System;
using System.Collections.Generic; // Dictionary<TKey, TValue>를 사용하려면 필요합니다.

// 상황: 학생 점수 관리
// Key: 학생 이름(string), Value: 점수(int)
Dictionary<string, int> studentScores = new Dictionary<string, int>();

// 1. 데이터 추가
studentScores.Add("김민준", 95);
studentScores.Add("안영호", 88);
studentScores.Add("홍길동", 99);
studentScores["신재아"] = 100; // 인덱서(indexer)를 사용한 추가/수정

// 2. 데이터 조회
Console.WriteLine($"김민준의 점수: {studentScores["김민준"]}");

// 3. 데이터 수정
studentScores["안영호"] = 92; // 안영호의 점수를 92로 수정

// 4. 데이터 삭제
studentScores.Remove("홍길동");

// 5. 안전한 조회
string studentName = "홍길동";
if (studentScores.ContainsKey(studentName))
{
    Console.WriteLine($"{studentName}의 점수: {studentScores[studentName]}");
}
else
{
    Console.WriteLine($"{studentName}의 점수 정보가 없습니다.");
}

// 6. 전체 데이터 순회
Console.WriteLine("\n--- 전체 학생 점수 ---");
foreach (var student in studentScores) // var는 KeyValuePair<string, int> 타입
{
    Console.WriteLine($"{student.Key}: {student.Value}점");
}

[실행 결과]

김민준의 점수: 95
홍길동의 점수 정보가 없습니다.

--- 전체 학생 점수 ---
김민준: 95점
안영호: 92점
신재아: 100점

4)정리

이제 우리는 데이터의 목적과 규칙에 따라 적절한 컬렉션을 선택할 수 있게 되었습니다.

제네릭 컬렉션자료 구조(Data Structure)주 사용처
Queue선입선출(FIFO)대기열, 순차적 작업 처리, 너비 우선 탐색(BFS)
Stack후입선출(LIFO)실행 취소, 재귀 알고리즘, 깊이 우선 탐색(DFS)
Dictionary해시 테이블(Hash Table)고유 키를 통한 빠른 데이터 검색 및 관리
profile
🚀 미래의 엔지니어를 꿈꾸는 훈련생의 기록 📝

0개의 댓글