본문 바로가기

유니티(자료구조1) _ 멋쟁이사자처럼 유니티 부트캠프 후기 35회차

@salmu2025. 7. 7. 16:11
반응형

[35회차 수업내용] 250707 

  1. 자료구조 개요 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>
  • Pythonlist (기본 내장형이 동적 배열 구조)
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 행동 순서 관리- 애니메이션 순차 실행

 

 

자료구조 이름들이 매우 직관적이라는 생각이 들었다. 각각의 자료구조는 다양한 활용을 위한 도구와 같아서, 상황에 맞게 적절히 사용할 수 있다는 점이 인상적이었다. 이번 공부 내용을 기억해두었다가, 필요할 때 ‘지금 이런 구조가 적합하지 않을까?’ 하고 다시 돌아와 활용할 수 있을 것 같다.

반응형
salmu
@salmu :: SMU 각종 기록

목차