[35회차 수업내용] 250707
- 자료구조 개요 2. 메모리 구조 3. 배열 4. 문자열 5. 리스트(List) 6.스택 (Stack) 7. 큐 (Queue) 8. 덱 (Deque) 9.자료구조 변환
1. 자료구조
: 데이터를 효율적으로 접근하고 활용할 수 있게 저장하고 관리하는것
1.1 단순구조
- 프로그래밍에서 사용되는 기본적인 데이터 타입
- 예: int, float, char, bool 등
1.2 선형구조
- 데이터가 일렬로 나열되어 있고, 1:1 관계
- 메모리 상에서 연속(정적) 또는 링크(동적)로 연결
| 배열 (Array) | 고정 크기, 인덱스로 빠른 접근 |
| 리스트 (List) | 가변 크기, 내부적으로 배열 기반 |
| 스택 (Stack) | LIFO 구조, Push/Pop |
| 큐 (Queue) | FIFO 구조, Enqueue/Dequeue |
1.3 비선형구조
- 1:N 또는 N:N 관계, 계층적/복잡한 구조
| 트리 (Tree) | 계층형 구조, 부모-자식 관계 |
| 그래프 (Graph) | 정점(Node)과 간선(Edge)으로 구성된 관계형 구조 |
1.4 파일구조
- 파일 단위로 데이터를 저장하고 처리하는 구조
- 예: 순차 파일, 색인 파일, 직접 접근 파일
2. 메모리 : 사용하는 데이터가 저장되는 곳

용도에 맞는 메모리 구조를 나눠야
불필요한 낭비를 줄이고 안정성을 높일 수 있음.
[요약]
| 코드 영역 = 설명서 | 프로그램 명령어 | 컴파일 타임 | 읽기 전용 |
| 데이터 영역 = 항상 유지되는 정보 | 전역/정적 변수 | 컴파일 타임 | 프로그램 종료 시까지 유지 |
| 힙 영역 = 창고 | 동적 할당 데이터 | 런타임 | 사용자가 필요할 때 할당/해제 |
| 스택 영역 = 메모장 | 지역/매개 변수 | 컴파일 타임 | 함수 호출 시 사용, 자동 할당/해제 |
2.1 코드 영역 (Code Segment)
:프로그램의 기계어 코드(명령어)가 저장되는 메모리 공간
:함수나 조건문, 반복문 같은 코드들이 컴파일되어 기계어로 변환된 뒤 이 영역에 저장
- 컴파일 시점에 결정되고 프로그램 실행 시 메모리에 로드됨
- 읽기 전용으로 설정돼 있어, 실행 도중에는 수정할 수 없음.
[활용 및 이유]
- 보안: 악성 코드가 실행 중에 메모리 조작 못하게 방지
- 안정성: 실수로 코드가 덮어쓰이는 걸 막음
- 대부분의 운영체제는 코드 영역을 읽기 전용으로 설정
2.2 데이터 영역 (Data Segment)
:전역 변수, static 변수, const 상수 등이 저장되는 메모리 공간
- 프로그램 실행과 함께 메모리에 올라오고, 프로그램이 끝날 때까지 유지 (프로그램 종료 시 운영체제가 자동 해제)
- 런타임 중 크기 변화 X
[주의]
- 전역/static 변수는 계속 메모리를 점유하므로 남발 시 메모리 낭비 발생 가능
- 값이 남아 있음을 모르고 재사용하면 → 예기치 않은 동작 유발
- 스택에 안 쌓이고 프로그램 전체에서 유지된다는 걸 이해해야 올바르게 사용 가능
2.3 힙 영역 (Heap)
: new, malloc 키워드의 통해 동적으로 생성한 객체나 배열(참조형 데이터)이 저장되는 메모리 공간
- 런타임 중 필요에 따라 할당되며, 개발자 또는 가비지 컬렉터(GC)가 해제해야 함.
- C/C++은 개발자가 직접 해제 (free, delete) / Java, C# 등은 GC가 자동 회수
- 힙 영역은 프로그램이 실행되는 ‘런타임’ 동안 할당되는 메모리 공간
- 프로그램이 종료되면 힙에 할당된 모든 메모리는 운영체제에 의해 해제되어 사라짐
- 런타임 중 힙 메모리는 계속 동적으로 늘어나고 줄어들 수 있음
[GC가 작동하는 조건]
1. 객체에 더 이상 참조가 없을 때→ 그 객체는 ‘가비지’가 되어 회수 대상이 됨
2. 힙 메모리가 부족해질 때 → 시스템이 메모리를 확보하려고 GC를 실행
+ 강제 실행도 가능
[활용 및 이유]
- 유연성: 프로그램 실행 중에도 크기가 변하는 데이터를 저장 가능 (ex. 사용자 입력에 따라 배열 크기 결정 등)
- 대용량 데이터 처리: 스택은 제한이 있지만 힙은 상대적으로 큰 메모리 사용 가능
- 객체 수명 관리: 스택처럼 자동 해제되지 않으므로, 객체를 원하는 만큼 오래 유지 가능
[주의 사항]
- 메모리 누수: C/C++에서는 할당 후 해제를 안 하면 메모리 계속 차지 → 프로그램 느려지거나 크래시
- GC 성능 저하: Java나 C#에서는 GC가 너무 자주 발생하면 성능이 저하될 수 있음
- 접근 속도: 스택보다 접근 속도가 느림 (포인터(=주소) 기반, 캐시(최근 저장된 데이터)와 멀리 있음)
2.4 스택 영역 (Stack)
: 함수가 호출될 때 생성되는 지역 변수, 매개변수, 반환 주소 등이 저장되는 메모리 공간
- 함수 호출 시 쌓이고, 함수 종료 시 자동으로 제거됨
- LIFO(Last-In, First-Out) 구조 — 가장 나중에 들어온 게 가장 먼저 나감
[활용 및 이유]
- 속도: CPU와 가까운 위치에 있고, 접근 주소가 고정되어 있어 접근 속도가 매우 빠름
- 자동 관리: 함수가 끝나면 지역 변수 등이 자동으로 사라져, 메모리 관리 부담이 적음
- 재귀, 함수 호출 흐름 관리: 호출 정보를 저장하여 함수 호출/복귀를 정확히 처리
[주의 사항]
- 메모리 제한: 스택은 크기가 제한되어 있어, 너무 깊은 재귀 호출은 스택 오버플로우 발생 (예: 무한 재귀, 큰 배열 선언 등)
- 수명 짧음: 스택 변수는 함수가 끝나면 사라지므로, 함수 외부에서 사용 불가
- 동적 크기 할당 불가: 일반적으로 컴파일 타임에 크기가 정해져야 함 (예외: VLA 등)
3. 배열
3.1 정적배열 = Array : 메모리 공간을 미리 만들어두고 사용하는 자료구조
→ 배열의 크기가 고정되어 있고, 컴파일 시 혹은 실행 시에 할당되며 중간에 크기를 바꿀 수 없음.
int[] array; // 배열 선언
int[] array = { 1, 2, 3, 4, 5 }; // 배열 선언과 초기화
int[] array = new int[5]; // 배열 선언과 공간만 할당 (모든 값은 기본값: 0)
int[] array = new int[5] { 1, 2, 3, 4, 5 }; // 배열 선언, 공간 할당(크기명시), 초기화
- 데이터 크기를 미리 알고 있을 때 (예: 요일 7개, 월 12개, 고정된 과목 수 등)
- 속도가 중요할 때
- 구조가 단순하고, 공간도 여유가 있을 때
3.2 다차원배열 = multidimensional Array : 행과 열로 구성된 고정 메모리 자료구조
-> n차원 (C#에서는 최대 32차원)
- 고정 크기: 한 번 선언하면 크기(각 차원 길이)는 바꿀 수 없음
- 연속된 메모리에 저장됨 (C#, C++ 등은 다차원 배열도 내부적으로 1차원 메모리 공간에 순차적으로 저장)
- 접근할 때 캐시 효율이 떨어질 수 있음 (특히 3차원 이상)
- 사용하지 않는 공간이 많으면 메모리 낭비가 심함 (예: int[100, 100] 선언하고 5개만 씀)
int[,] array = new int[3, 3]; // 3행 3열을 가진 2차원 배열
int[,,] array2 = new int[2, 3, 4]; // 3차원 배열
int[,] matrix = new int[3,3];
matrix[1,2] = 25;
Debug.Log(matrix[1,2]); // 25
3행 3열
[ [0,0] [0,1] [0,2] ]
[ [1,0] [1,1] [1,2] ]
[ [2,0] [2,1] [2,2] ]
* 언제 쓰면 좋을까?
- 2D 게임에서 맵 구현
- 행렬(Matrix) 계산
- 이미지 처리 (픽셀 좌표)
- 테이블 형태의 데이터 처리
3.3 가변 배열 = Jagged Array
= 배열안에 배열 = ex 배열이 n개있는 배열
:각 행(또는 인덱스)의 크기가 서로 다를 수 있는 배열
- 선언만 하면 내부 배열은 null 상태 → 직접 new로 초기화해야 함
- 겉에 있는 배열(행 배열)은 만들어졌지만, 각 내부 배열(열 배열)은 아직 만들지 않았기 때문에 null
- (다른 배열은 모든 칸이 0으로 초기화됨)
int[][] numbers = new int[3][];
numbers[0] = new int[2] { 1, 2, 3 };
numbers[1] = new int[4] { 4, 5 };
numbers[2] = new int[3] { 6, 7, 8, 9 };
int[][] jagged = new int[3][]; // 행 3개, 아직 열은 안 정해짐
jagged[0] = new int[2]; // 첫 번째 행은 2열
jagged[1] = new int[4]; // 두 번째 행은 4열
jagged[2] = new int[1]; // 세 번째 행은 1열
jagged[1][3] = 99; // 두 번째 행의 네 번째 열에 값 할당
3.4 다차원배열 vs 가변배열
| 이름 | 다차원 배열 (Multidimensional Array) | 가변 배열 (Jagged Array) |
| 구조 | 하나의 연속된 2차원 메모리 블록 | 각 행이 별도의 1차원 배열 |
| 행 길이 | 모든 행의 열 개수가 같음 | 각 행의 열 개수가 다를 수 있음 |
| 메모리 | 연속된 메모리 블록 | 배열 각각 따로 힙에 저장 |
| 선언 예 | new int[2, 3] | new int[2][]; arr[0] = new int[3]; |
| 인덱싱 | arr[1,2] | arr[1][2] |
3.5 동적배열 (Dynamic Array)
: 실행 중에 크기를 유동적으로 늘릴 수 있는 배열
: 1개씩 늘리는게 아니라 150% ~ 200% 정도도 잡고 생성 (메모리를 할당하고 복사하는 과정이 자동화된 것)
- 크기 늘어날 때마다 배열을 복사 / 메모리 : 더 많이 쓸 수도 있음
- C# → List<T>
- Python → list (기본 내장형이 동적 배열 구조)
List<int> list = new List<int>();
list.Add(10);
list.Add(20);
list.Add(30);
: Count, Capacity, Remove(), Insert() 등
3.6 자료구조 이해_ 정적배열에서 배열 크기 늘려보기 (동적 배열 구현)
public class DynamicArray : MonoBehaviour
{
// 내부 배열 선언 (처음에는 크기가 0인 빈 배열로 시작)
private object[] array = new object[0];
// 배열에 ㅅ새 객체를 추가하는 메서드
public void Add(object o)
{
// 기존 배열보다 1칸 더 큰 새 배열 생성
var temp = new object[array.Length + 1];
// 기존 배열의 요소들을 새 배열로 복사
for (int i = 0; i < array.Length; i++)
temp[i] = array[i];
// 새 배열을 현재 배열로 대체
array = temp;
// 마지막 칸에 새 객체 추가
array[array.Length - 1] = o;
}
}
-활용해보자
그러면 여기서 temp는? 함수안에만 작용하는 지역변수 = 스택에!
| array 필드 (참조값) | DynamicArray 인스턴스 안 → 힙 |
| array가 가리키는 배열 | new object[] → 힙 |
| temp 변수 | 함수 안에서 쓰이는 지역 변수 → 스택 |
| temp가 가리키는 배열 | new object[] → 힙 |
public class DynamicArray : MonoBehaviour
{
// 내부 배열 (실제 데이터를 저장할 공간)
private object[] array = new object[0];
// 배열이 꽉 찼을 때 몇 배로 확장할지 결정하는 상수
private const int CROWTH_FACTOR = 2;
// 현재 저장된 요소의 개수를 나타내는 정수형 프로퍼티
// 외부에서는 값을 읽을 수만 있고(get), 클래스 내부에서만 수정 가능(set)
public int Count { get; private set; }
// 배열의 전체 용량 (확보된 공간의 크기)
public int Capacity
{
get { return array.Length; }
}
// 생성자: 초기 용량을 받아 배열을 생성 (기본값은 16)
public DynamicArray(int capacity = 16)
{
array = new object[capacity];
Count = 0;
}
// 요소 추가 메서드
public void Add(object o)
{
// 배열이 꽉 찼다면 → 크기를 CROWTH_FACTOR 배로 늘림
if (Count >= Capacity)
{
int newSize = Capacity * CROWTH_FACTOR;
var temp = new object[newSize];
// 기존 요소들을 새 배열로 복사
for (int i = 0; i < array.Length; i++)
temp[i] = array[i];
// 새 배열을 기존 배열로 교체
array = temp;
}
// 현재 위치에 새 요소 추가하고 Count 증가
array[Count] = o;
Count++;
}
// 특정 인덱스의 요소를 가져오는 메서드
public object Get(int index)
{
// 인덱스가 유효 범위를 벗어나면 예외 발생
if (index > Capacity - 1)
throw new ApplicationException("Object not found");
return array[index];
}
}
-활용해보자
| 클래스 인스턴스 필드 | array, Count | 힙 (Heap) | 클래스 인스턴스가 힙에 생성되면 필드도 함께 저장됨 |
| 배열 객체 | new object[0], new object[newSize] | 힙 (Heap) | new 키워드로 생성된 배열은 모두 힙에 저장 |
| 상수 필드 | private const int CROWTH_FACTOR = 2; | 코드 영역 (Code Segment) | const는 컴파일 시점에 값이 결정되며 코드 영역에 저장됨 |
| 메서드 | Add(), Get(), DynamicArray() | 코드 영역 (Code Segment) | 메서드의 명령어(기계어)가 저장됨. 실행 불가능한 읽기 전용 영역 |
| 지역 변수 | int newSize, var temp, int i | 스택 (Stack) | 메서드 실행 시 생성되는 임시 변수들. 메서드 종료 시 소멸 |
| 매개변수 | object o, int index, int capacity | 스택 (Stack) | 메서드 호출 시 인자로 전달되는 값들 |
| 프로퍼티 자체 | get { return array.Length; } | 코드 영역 (메서드처럼 취급됨) | get 접근자 로직은 함수처럼 실행되며 코드 영역에 저장됨 |
| 프로퍼티 값 | Count의 값 | 힙 (Heap) | 실제 값은 클래스 인스턴스 필드로 저장되므로 힙에 존재 |
4. 문자열 : 문자(char)들의 배열로 구성된 데이터 타입
배열과 문자열
string[] words = new string[] { "Hello", "World", "Unity" };
// 배열과 문자열(참조형)은 힙에 저장됨
// indexer로 접근
Debug.Log(words[0]); // Hello
Debug.Log(words[1]); // World
Debug.Log(words[2]); // Unity
// 반복문을 활용한 출력
foreach (string word in words)
{
Debug.Log(word);
}
//word는 스택에 저장됨
//Hello
//World
//Unity
[문자열 연결 및 출력]
string name = "철수";
int age = 20;
string str1 = "이름은 " + name + " / 나이는 " + age;
Debug.Log(str1);
// 이름은 철수 / 나이는 20
// age가 int인데도 자동으로 문자열로 변환됨 (암시적 ToString())
string str2 = string.Format("이름은 {0} / 나이는 {1}", name, age);
Debug.Log(str2);
// 이름은 철수 / 나이는 20
// 인덱스 기반 포맷팅 , 다국어 처리나 포맷 변경에 유리
//String.Format(포맷문자열(문자열 틀template), 값1, 값2, ...);
string str3 = $"이름은 {name} / 나이는 {age}";
Debug.Log(str3);
// 이름은 철수 / 나이는 20
// 문자열 보간, {}로 변수나 표현식 삽입가능
string text = "Hello Unity ";
Debug.Log(text.Length); // 길이: 13 (공백포함)
Debug.Log(text.Trim()); // 문자열 양쪽의 공백 제거: "Hello Unity"
Debug.Log(text.ToUpper()); // 대문자: "HELLO UNITY"
Debug.Log(text.ToLower()); // 소문자: "hello unity"
Debug.Log(text.Contains("Unity")); // 포함 여부: true
Debug.Log(text.Replace("Unity", "C#")); // 교체 : "Hello C#"
string path = "C:\\User\\MyFolder"; // 역슬래시(\) 표현
string multiLine = "Hello\nWorld"; // 줄바꿈 (\n)
Debug.Log(path); // 출력: C:\User\MyFolder
Debug.Log(multiLine);
// 출력:
// Hello
// World
| \\ | 백슬래시 (\) 자체를 표현 |
| \n | 줄바꿈 (newline) |
| \t | 탭 (tab) |
| \" | 큰따옴표 출력 |
4.1 ToString()
int number = 12345;
var s1 = number.ToString(); // 문자열 반환
var s2 = number.ToString("#"); //#는 숫자 출력(0은 빈문자열 출력)
var s3 = number.ToString("0000000"); // 7자리로 표현
var s4 = number.ToString("#,0"); //천 단위 콤마 추가
# 결과값
s1 : 12345
s2 : 12345
s3 : 0012345
s4 : 12,345
decimal distance = 9876.123m;
var s5 = distance.ToString(); // 문자열 반환
var s6 = distance.ToString("#"); //정수 부분만 출력 (소수점 버림)// #.#이면? -> 9876.1 출력
var s7 = distance.ToString("#,0.0"); //천 단위 콤마, 소수점 첫째 자리까지 출력
var s8 = distance.ToString("#,0.0000"); //천 단위 콤마, 소수점 4자리 출력 (0 채움)
# 결과값
s5 : 9876.123
s6 : 9876
s7 : 9876.1
s8 : 9876.1230
var s9 = string.Format("{0,10:#,0}", number); 총 10자리 공간 확보, 오른쪽 정렬, 천 단위 콤마
var s10 = string.Format("{0,10}", distance); 총 10자리 공간 확보, 기본 ToString()
var s11 = string.Format("{0,10:0.0}", distance); 총 10자리 공간 확보, 소수점 첫째 자리까지 출력
# 결과값
s9 : 12345
s10 : 9876.123
s11 : 9876.1
5. 리스트(List)
:메모리 공간을 유동적으로 사용하는 자료구조 → 동적 배열
List<int> list = new List<int>(); // 리스트 선언
List<int> list = new List<int>() { 1, 2, 3, 4, 5 }; // 리스트 선언과 초기화
5.1 리스트 추가, 삭제, 삽입
// # 데이터 추가
list.Add(value); // 리스트의 끝에 value 값을 추가
for (int i = 0; i < 10; i++)
list.Add(i); // 0부터 9까지의 숫자를 리스트에 순차적으로 추가
// # 특정 위치에 데이터 삽입
list.Insert(index, value); // 지정한 index 위치에 value 값을 삽입
list.Insert(2, 100); // 리스트의 3번째 위치(index 2)에 100을 삽입
// # 특정 값을 가진 데이터 삭제
list.Remove(value); // 리스트에서 처음 발견되는 value 값을 삭제
list.Remove(2); // 값이 2인 첫 번째 항목을 삭제
// # 특정 인덱스에 위치한 데이터 삭제
list.RemoveAt(index); // 지정한 index 위치에 있는 데이터를 삭제
list.RemoveAt(2); // 리스트의 3번째 항목(index 2)을 삭제
// # 여러 개의 연속된 데이터 삭제
list.RemoveRange(index, amount); // index부터 amount개의 데이터를 삭제
list.RemoveRange(2, 5); // index 2부터 시작해 총 5개 항목 삭제
// # 조건에 맞는 모든 데이터 삭제
list.RemoveAll(x => 조건); // 조건에 맞는 모든 항목을 삭제
list.RemoveAll(x => x > 5); // 값이 5보다 큰 모든 항목을 삭제
// # 리스트의 모든 데이터 삭제
list.Clear(); // 리스트에 저장된 모든 데이터를 삭제 (빈 리스트로 만듦)
5.2 List 추가, 출력 실습 코드
// 리스트에 있는 숫자들을 문자열로 이어 붙일 변수 선언 (처음은 빈 문자열)
string str = "";
// 리스트에 있는 모든 정수 i를 하나씩 반복
foreach (int i in list)
{
// i를 문자열로 바꾸고 뒤에 쉼표와 공백을 붙여서 str에 추가
str += i.ToString() + ", ";
}
Debug.Log(str);
- list.Contains(값)→ 존재하지 않으면 false를 반환 → 리스트 안에 해당 값이 존재하면 true
// 데이터를 담기 위한 사용자 정의 클래스
// 헷갈려서 실제 값은 data1 -> dataA로 바꿔서 표현한 코드
public class DataClass
{
public int data1; // 정수형 데이터를 저장하는 멤버 변수 (객체가 가진 속성)
public float data2; // 실수형 데이터
public string data3; // 문자열 데이터
// 생성자(Constructor): 객체 생성 시 데이터를 초기화
public DataClass(int dataA, float dataB, string dataC) // 매개변수
{
this.data1 = dataA; // 생성자의 매개변수 'data1' 값을 이 객체의 'data1' 변수에 저장
this.data2 = dataB; // 매개변수 data2를 멤버 변수에 할당
this.data3 = dataC; // 매개변수 data3을 멤버 변수에 할당
}
}
// 유니티 컴포넌트 클래스
public class ExampleClass : MonoBehaviour
{
// DataClass 타입의 리스트를 선언 및 초기화
public List<DataClass> datas = new List<DataClass>();
void Start()
{
// DataClass 인스턴스를 생성하여 리스트에 추가
datas.Add(new DataClass(1, 2f, "안녕하세요.")); // data1=1, data2=2f, data3="안녕하세요."
datas.Add(new DataClass(3, 4f, "유니티 엔진")); // 두 번째 객체: data1=3, data2=4f, data3="유니티 엔진"
// 리스트에 저장된 데이터들을 반복하며 출력
foreach (var data in datas)
{
Debug.Log("Data1 : " + data.data1); // 정수 출력
Debug.Log("Data2 : " + data.data2); // 실수 출력
Debug.Log("Data3 : " + data.data3); // 문자열 출력
//Data1 : 1
//Data2 : 2
//Data3 : 안녕하세요.
//Data1 : 3
//Data2 : 4
//Data3 : 유니티 엔진
}
}
}
5.3 순차 리스트 (ArrayList)
: 다양한 자료형(int, float, string 등)을 모두 object 타입으로 저장할 수 있는 자료구조
-
- 타입 안정성 부족: 잘못된 형변환 시 런타임 오류 발생 가능
- → 요즘은 List<T> 제네릭 컬렉션 사용을 권장
ArrayList arrayList = new ArrayList();
# 추가
arrayList.Add(10); // int -> object (Boxing 발생)
arrayList.Add(3.14f); // float -> object (Boxing 발생)
arrayList.Add("123"); // string -> object (Boxing 발생)
int value = (int)arrayList[0]; // object -> int (UnBoxing 발생)
5.4 연결 리스트 (Linked List)
- 각 요소(노드)가 서로 연결된 형태로 구성된 자료구조
- 메모리상 연속적이지 않고, 각 노드가 다음 노드(또는 이전 노드)의 참조를 가짐
- 단일 연결 리스트(Singly Linked List) → 한 방향 연결
- 이중 연결 리스트(Doubly Linked List) → 앞뒤로 연결됨

// LinkedList 선언 (int형 데이터를 저장)
LinkedList<int> linkedList = new LinkedList<int>();
// 요소 추가
linkedList.AddLast(10); // 맨 뒤에 10 추가
linkedList.AddLast(20); // 맨 뒤에 20 추가
linkedList.AddLast(30); // 맨 뒤에 30 추가
// 요소 접근
int firstVal = linkedList.First.Value; // 첫 번째 노드 값 (10)
int lastVal = linkedList.Last.Value; // 마지막 노드 값 (30)
// 요소 삭제
linkedList.RemoveLast(); // 마지막 노드(30) 삭제
// LinkedList<T>에서는 Add() 라는 메서드는 없음
// AddLast, AddFirst, AddBefore, AddAfter
6. 스택 (Stack)
: 나중에 추가된 데이터가 가장 먼저 나오는 자료구조
→ LIFO(Last In, First Out) 구조 = 후입선출

Stack intStack = new Stack<int>();
//추가 -> Push : 스택의 맨 위에 데이터를 추가하는 함수
intStack.Push(10);
//삭제 -> Pop : 스택의 맨 위에 있는 데이터를 제거하는 함수. 데이터 타입에 맞는 타입을 반환
intStack.Pop();
//확인 -> Peek : 현재 나올 대상을 확인만 하는 기능
intStack.Peek();
7. 큐 (Queue)
: 먼저 추가된 데이터가 가장 먼저 나오는 자료구조
→ FIFO(First In, First Out) 구조

Queue<int> intQueue = new Queue<int>();
// 추가 -> Enqueue : 큐에 데이터를 추가하는 함수. 큐의 맨 끝에 데이터가 추가
intQueue.EnQueue(10);
// 삭제 -> Dequeue : 큐에 데이터를 제거하는 함수. 큐의 맨 처음 데이터가 제거
intQueue.Dequeue();
// 확인 -> Peek : 현재 나올 대상을 확인만 하는 기능
intQueue.Peek();
// 모든 데이터 삭제
intQueue.Clear();
// 데이터가 있는지 확인
intQueue.Contains(1);
8. 덱 (Deque)
: 양방향으로 데이터가 들어갈 수 있고, 나올 수 있는 자료구조
: C# 표준 라이브러리에는 Stack<T>와 Queue<T> 타입은 있지만, 따로 Deque<T> 타입은 없음
LinkedList<int> deque = new LinkedList<int>();
// 앞/뒤 삽입
deque.AddFirst(1); // 앞
deque.AddLast(2); // 뒤
// 앞/뒤 제거
deque.RemoveFirst();
deque.RemoveLast();
9. 자료구조 변환
9.1 배열(Array) → Stack / Queue 생성
int[] array = new int[3] { 1, 2, 3 };
Stack<int> intStack = new Stack<int>(array); // Stack의 Top은 3 (배열 끝 요소)
Queue<int> intQueue = new Queue<int>(array); // Queue의 Front는 1 (배열 첫 요소)
Debug.Log(intStack.Peek()); // 출력: 3
Debug.Log(intQueue.Peek()); // 출력: 1
9.2 Stack / Queue → 배열(Array) 변환
- ToArray()
int[] arrFromStack = stack.ToArray();
int[] arrFromQueue = queue.ToArray();
9.3 리스트(List) → Stack / Queue 생성
List<int> list = new List<int> { 1, 2, 3 };
Stack<int> stack = new Stack<int>(list); // Top: 3 (마지막 요소가 top)
Queue<int> queue = new Queue<int>(list); // Front: 1 (첫 요소가 front)
[활용]
| 스택 (Stack) | 후입선출 (LIFO) | - Undo/Redo 기능- 게임 상태 관리 (화면 전환)- DFS, 재귀적 알고리즘 |
| 큐 (Queue) | 선입선출 (FIFO) | - 이벤트 처리 대기열- AI 행동 순서 관리- 애니메이션 순차 실행 |
자료구조 이름들이 매우 직관적이라는 생각이 들었다. 각각의 자료구조는 다양한 활용을 위한 도구와 같아서, 상황에 맞게 적절히 사용할 수 있다는 점이 인상적이었다. 이번 공부 내용을 기억해두었다가, 필요할 때 ‘지금 이런 구조가 적합하지 않을까?’ 하고 다시 돌아와 활용할 수 있을 것 같다.
'프로그래밍 > 유니티 부트캠프' 카테고리의 다른 글
| 유니티(리스트, 스택 실습 _ 하노이의 탑) _ 멋쟁이사자처럼 유니티 부트캠프 후기 37회차 (0) | 2025.07.10 |
|---|---|
| 유니티(자료구조2, 형상관리 깃브랜치, 배열 예제_3D_폭탄) _ 멋쟁이사자처럼 유니티 부트캠프 후기 36회차 (0) | 2025.07.08 |
| 유니티(몬스터 행동패턴 (인벤토리 기능/ 플랫포머게임 마무리 / 2D Rigging) _ 멋쟁이사자처럼 유니티 부트캠프 후기 34회차 (3) | 2025.07.05 |
| 유니티(공격 판정 / 체력바 / 아이템 드롭) _ 멋쟁이사자처럼 유니티 부트캠프 후기 33회차 (1) | 2025.07.05 |
| 유니티(몬스터 행동패턴 (Finite State Machine, 유한 상태 머신) 만들기 ) _ 멋쟁이사자처럼 유니티 부트캠프 후기 32회차 (1) | 2025.07.05 |