[SKKU DT] 44일차 -유니티 스택(Stack), 큐(Queue), 스택을 이용한 팝업 예제, 일반화 프로그래밍, 배열(Array)

2024. 1. 3. 18:25SKKU DT

728x90
반응형
 

[SKKU DT] 43일차 -유니티 오브젝트 풀(Object Pool)

3D -공간 디자인, 라이팅, 3D 오브젝트 UI -Autolayout, TableView 서버 -JSON 배포 -Window-인스톨러/Web-최적화/Mobile-최적화,배포 데이터처리 C# -자료구조, 알고리즘 협업 -소스코드 관리, 작업 관리 오브젝트

lightbakery.tistory.com


이전 글에 이어서...

 

 

패널 프리팹을 보면 Image가 비어있는 것을 볼 수 있다.

 

 

Panel 프리팹을 Image에 드래그앤 드랍 한다.

 

 

PanelManager에서 panelCount를 선언하고 하나씩 증가하도록 수정

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PanelManager : MonoBehaviour
{
    [SerializeField] GameObject panelPrefab;
    [SerializeField] Transform parent;

    int panelCount = 0;

    //흰색 뺀 색상을 배열에 정의
    Color[] colors = new Color[4] { Color.black, Color.blue, Color.yellow, Color.green };
    public void Open()
    {
        GameObject panelObject = Instantiate(panelPrefab, parent);
        Panel panel = panelObject.GetComponent<Panel>();
        panel.IndexText = panelCount++;
        panel.manager = this;
        panel.ChangeColor(colors[Random.Range(0,3)]);
    }

    public void Close()
    {

    }
}

이미지도 넣었고 패널도 증가하도록 설정하여 적용된 것을 볼 수 있다.

 

 

Previous 버튼을 누를 때 패널이 닫히게 하기

Panel 스크립트 수정. 굳이 Close를 PanelManager 스크립트에게 위임하지 않고 Destroy(gameObject);로 스스로 지울 수 있다.

 

 

하지만 우리는 PanelManager 스크립트를 이용해서 Close를 실행할 것이다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;

public class Panel : MonoBehaviour
{
    //패널 가운데 텍스트 접근
    [SerializeField] private TMP_Text indexText;
    //패널 색상 변경 위해 색상 접근
    [SerializeField] private Image image;

    //PanelManager 선언
    public PanelManager manager; //프리팹이라 SerializeField를 사용할 수 없다.

    /*
    public int IndexText { get; set; } //프로퍼티의 축약형. 변수처럼 쓸수있고 함수도 사용할 수 있다.
    public int IndexText2; //변수. 유효한 값을 판단할 수 없다. 프로퍼티에서는 set 중괄호 안에 if, else문을 넣을 수 있다.
    */

    //프로퍼티를 사용하면 아래와 같다.
    public int index; //저장을 위한 변수. 아예 지우고 아래의 index를 Index로 대문자로 쓰기도 한다.
    public int IndexText //값을 저장하기 위해서 접근할 수 있는 속성을 가진 프로퍼티
    {
        get
        {
            return index;
        }
        set
        {
            index = value;
            indexText.text = index.ToString();
        }
    }
    /*
    프로퍼티를 쓰기 때문에 SetPanelIndex는 쓰지 않는다.
    public void SetPanelIndex(int index) //세터 메서드: 값을 외부에서 받아서 전달하기 위한 메서드
    {
        indexText.text = index.ToString(); //매개변수 index를 문자열로 변환
    }
    */
    
    // Open 버튼 클릭시 호출되는 메서드
    public void Open()
    {
        manager.Open(); //manager 스크립트에게 위임
    }
    //Previous 버튼 클릭시 호출되는 메서드
    public void Close()
    {
        manager.Close(); //manager 스크립트에게 위임
    }

    /// <summary>
    /// 패널의 색상 변경 메서드
    /// </summary>
    /// <param name="color">변경할 색상</param>
    public void ChangeColor(Color color) //컬러 변경 메서드 생성
    {
        image.color = color;
    }
}

 

 

PanelManager 수정. Stack을 사용한다. 마지막에 들어간 것이 가장 먼저 나오는 First In Last Out 형태이다.

//스택 생성
Stack<GameObject> panelStack = new Stack<GameObject>();
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PanelManager : MonoBehaviour
{
    [SerializeField] GameObject panelPrefab;
    [SerializeField] Transform parent;

    //스택 생성
    Stack<GameObject> panelStack = new Stack<GameObject>();

    //int panelCount = 0; //panelStack.Count;를 씀으로써 지워진다.

    //흰색 뺀 색상을 배열에 정의
    Color[] colors = new Color[4] { Color.black, Color.blue, Color.yellow, Color.green };
    public void Open()
    {
        GameObject panelObject = Instantiate(panelPrefab, parent);
        //Push로 게임오브젝트인 panelObject를 넣는다.
        panelStack.Push(panelObject);

        Panel panel = panelObject.GetComponent<Panel>();
        panel.IndexText = panelStack.Count; //panelCount 변수를 사용하지 않고 Count 함수를 가져다 쓸 수 있다. get만 가능한 읽기 전용.
        panel.manager = this;
        panel.ChangeColor(colors[Random.Range(0,3)]);
    }

    public void Close()
    {
        GameObject lastPanelObject = panelStack.Pop(); //마지막 패널을 Pop 시키면 뽑아져 나오면서 Stack에서 삭제 된다.
        Destroy(lastPanelObject); //마지막 패널을 삭제한다.
    }
}

이제 숫자가 이상하게 변하지 않고 차례대로 커지고 작아진다.

 

 


 

 

 

DOTween (HOTween v2) | 애니메이션 도구 | Unity Asset Store

Use the DOTween (HOTween v2) tool from Demigiant on your next project. Find this & more animation tools on the Unity Asset Store.

assetstore.unity.com

패널이 켜지고 꺼질 때의 효과를 주기 위해서 에셋스토어에서 DOTween을 받는다.

Setup을 하고 Apply 한다.

 

 

PanelManager 스크립트 수정

네임스페이스 추가

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class PanelManager : MonoBehaviour
{
    [SerializeField] GameObject panelPrefab;
    [SerializeField] Transform parent;

    //스택 생성
    Stack<GameObject> panelStack = new Stack<GameObject>();

    //int panelCount = 0; //panelStack.Count;를 씀으로써 지워진다.

    //흰색 뺀 색상을 배열에 정의
    Color[] colors = new Color[4] { Color.black, Color.blue, Color.yellow, Color.green };
    public void Open()
    {
        GameObject panelObject = Instantiate(panelPrefab, parent);
        //Push로 게임오브젝트인 panelObject를 넣는다.
        panelStack.Push(panelObject);

        panelObject.transform.localScale = Vector3.zero; //처음엔 스케일을 0으로 설정
        panelObject.transform.DOScale(1, 0.2f); //(스케일의 결과 값, 도달하는 데에 걸리는 시간)

        Panel panel = panelObject.GetComponent<Panel>();
        panel.IndexText = panelStack.Count; //panelCount 변수를 사용하지 않고 Count 함수를 가져다 쓸 수 있다. get만 가능한 읽기 전용.
        panel.manager = this;
        panel.ChangeColor(colors[Random.Range(0,3)]);
    }

    public void Close()
    {
        GameObject lastPanelObject = panelStack.Pop(); //마지막 패널을 Pop 시키면 뽑아져 나오면서 Stack에서 삭제 된다.
        Destroy(lastPanelObject); //마지막 패널을 삭제한다.
    }
}

 

 

끌 때도 애니메이션을 적용한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class PanelManager : MonoBehaviour
{
    [SerializeField] GameObject panelPrefab;
    [SerializeField] Transform parent;

    //스택 생성
    Stack<GameObject> panelStack = new Stack<GameObject>();

    //int panelCount = 0; //panelStack.Count;를 씀으로써 지워진다.

    //흰색 뺀 색상을 배열에 정의
    Color[] colors = new Color[4] { Color.black, Color.blue, Color.yellow, Color.green };
    public void Open()
    {
        GameObject panelObject = Instantiate(panelPrefab, parent);
        //Push로 게임오브젝트인 panelObject를 넣는다.
        panelStack.Push(panelObject);

        panelObject.transform.localScale = Vector3.zero; //처음엔 스케일을 0으로 설정
        panelObject.transform.DOScale(1, 0.2f); //(스케일의 결과 값, 도달하는 데에 걸리는 시간)

        Panel panel = panelObject.GetComponent<Panel>();
        panel.IndexText = panelStack.Count; //panelCount 변수를 사용하지 않고 Count 함수를 가져다 쓸 수 있다. get만 가능한 읽기 전용.
        panel.manager = this;
        panel.ChangeColor(colors[Random.Range(0,3)]);
    }

    public void Close()
    {
        GameObject lastPanelObject = panelStack.Pop(); //마지막 패널을 Pop 시키면 뽑아져 나오면서 Stack에서 삭제 된다.

        lastPanelObject.transform.DOScale(0, 0.2f).OnComplete(() =>
        {
            Destroy(lastPanelObject);
        }); //스케일 0으로, 0.2초 동안. OnComplete으로 애니메이션이 다 작동될 때까지 Destroy하지 않는다.
    }
}

켜질 때와 꺼질 때 애니메이션 적용 굿~

 

 

나만의 Stack 만들기?

**프로퍼티는 필드 값을 가져오거나 설정하는데 사용되며, 외부에서 프로퍼티에 접근하는 것은 변수에 직접 접근하는 것과 유사하게 보입니다. 그러나 프로퍼티는 내부적으로 메서드로 구현되어 있어 더 많은 제어를 제공하고, 간단한 계산이나 로직을 추가할 수 있습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyStack : MonoBehaviour
{
    List<int> values = new List<int>();

    //스택 생성
    Stack<int> myStack = new Stack<int>();
    
    //Stack에 저장된 요소의 수
    public int Count
    {
        get { return myStack.Count;}
    }

    public void Push(int value)
    {
        //Push로 value를 넣는다.
        myStack.Push(value);
    }

    public int Pop()
    {
        if (myStack.Count > 0)
        {
            return myStack.Pop();
        }
        else
        {
            Debug.Log("스택이 비어있습니다.");
            return -1;
        }
    }

    private void Start()
    {
        Push(10);
        Push(20);
        Push(30);

        Debug.Log("Pop: " + Pop()); //30
        Debug.Log("Pop: " + Pop()); //20
        Debug.Log("Pop: " + Pop()); //10

        Debug.Log("현재 스택의 요소 수: " + Count);
    }
}

GPT 친구의 도움을 받아 Stack의 예시를 하나 작성하였다.

 

 

Push로 입력한 순서는 10, 20, 30 순서지만 출력되는 값의 순서는 30, 20, 10으로 나오는 것을 볼 수 있다.

 

 


 

 

Stack 예시

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyStack : MonoBehaviour
{
    List<int> values = new List<int>();

    //Stack에 저장된 요소의 수
    public int Count
    {
        get { return values.Count; } //get으로 읽기만 가능하도록.
    }

    public void Push(int value)
    {
        values.Add(value);
    }

    public int Pop()
    {
        int idx = values.Count - 1; //인덱스는 카운트의 -1
        int result = values[idx]; //result는 리스트에서 인덱스의 값
        values.RemoveAt(idx); //인덱스 값을 지우고
        return result; //결과를 반환한다.
    }
}

 

 

Queue 예시

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyQueue : MonoBehaviour
{
    List<int> values = new List<int>();

    public int Count { get { return values.Count; } }

    public void Enqueue(int value)
    {
        values.Add(value);
    }

    public int Dequeue()
    {
        int idx = 0;
        int result = values[idx]; //첫 번째 값이 불러와진다.
        values.RemoveAt(idx);
        return result;
    }
}

 

 


 

 

일반화 프로그래밍

바로 직전의 Stack과 Queue코드를 일반화 프로그래밍으로 바꾸면, 값 형식 자리에 T를 넣을 수 있다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyStack<T> : MonoBehaviour
{
    List<T> values = new List<T>();

    //Stack에 저장된 요소의 수
    public int Count
    {
        get { return values.Count; } //get으로 읽기만 가능하도록.
    }

    public void Push(T value)
    {
        values.Add(value);
    }

    public T Pop()
    {
        int idx = values.Count - 1; //인덱스는 카운트의 -1
        T result = values[idx]; //result는 리스트에서 인덱스의 값
        values.RemoveAt(idx); //인덱스 값을 지우고
        return result; //결과를 반환한다.
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyQueue<T> : MonoBehaviour
{
    List<T> values = new List<T>();

    public int Count { get { return values.Count; } }

    public void Enqueue(T value)
    {
        values.Add(value);
    }

    public T Dequeue()
    {
        int idx = 0;
        T result = values[idx]; //첫 번째 값이 불러와진다.
        values.RemoveAt(idx);
        return result;
    }
}

 

 


 

 

바로 위에서 MyStack과 MyQueue를 T 제네릭으로 선언했기 때문에 새로운 스크립트에서도 가져와서 int 형을 대입해도 문제가 없다. 물론 string도 문제 없다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StackQueueExample : MonoBehaviour
{
    void Start()
    {
        MyStack<int> stack = new MyStack<int>(); //MyStack에서 정의했던 모든 T가 int 형으로 자동으로 바뀐다.

        stack.Push(1);
        stack.Push(2);
        stack.Push(3);
        stack.Push(4);
        stack.Push(5);
        stack.Push(6);

        while(stack.Count > 0)
        {
            int result = stack.Pop();
            Debug.Log(result);
        }

        MyQueue<int> queue = new MyQueue<int>();

        queue.Enqueue(1);
        queue.Enqueue(2);
        queue.Enqueue(3);
        queue.Enqueue(4);
        queue.Enqueue(5);
        queue.Enqueue(6);
        
        while(queue.Count > 0)
        {
            int result = queue.Dequeue();
            Debug.Log(result);
        }
    }
}

 

 


 

 

**Pop을 할 때 아무것도 없는데 pop하면 크래시가 날 수 있다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyStack : MonoBehaviour
{
    List<int> values = new List<int>();

    //Stack에 저장된 요소의 수
    public int Count
    {
        get { return values.Count; } //get으로 읽기만 가능하도록.
    }

    public void Push(int value)
    {
        values.Add(value);
    }

    public int Pop()
    {
        if(values.Count > 0)
        {
            int idx = values.Count - 1; //인덱스는 카운트의 -1
            int result = values[idx]; //result는 리스트에서 인덱스의 값
            values.RemoveAt(idx); //인덱스 값을 지우고
            return result; //결과를 반환한다.
        }
        else
        {
            return 0;
        }
    }
}

크래시가 나지 않는 안전장치로는, values.Count가 0보다 크면 Pop을 실행하고 아니면 0만 반환하게 할 수 있다. 이건 int형일 때만 가능.

 

 

제네릭에서는 return에 int형을 쓸 수 없다. 왜냐하면 아직 형이 정해지지 않은 T에 int를 확정지을 수 없기 때문.

 

 

다음과 같이 크래시를 예방할 수 있다. throw~ 부분을 추가하였다.

public T Pop()
{
    if(values.Count > 0)
    {
        int idx = values.Count - 1; //인덱스는 카운트의 -1
        T result = values[idx]; //result는 리스트에서 인덱스의 값
        values.RemoveAt(idx); //인덱스 값을 지우고
        return result; //결과를 반환한다.
    }
    else
    {
        throw new InvalidOperationException("MyStack Enpty");
    }
}

 

try ~ catch 문으로 묶으면, MyStack 스크립트에서 throw 된 exception이 try catch문으로 들어가면서 메시지가 출력된다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class StackQueueExample : MonoBehaviour
{
    void Start()
    {
        MyStack<int> stack = new MyStack<int>(); //MyStack에서 정의했던 모든 T가 int 형으로 자동으로 바뀐다.

        stack.Push(1);
        stack.Push(2);
        stack.Push(3);
        stack.Push(4);
        stack.Push(5);
        stack.Push(6);

        while(stack.Count > 0)
        {
            int result = stack.Pop();
            Debug.Log(result);
        }

        try
        {
            stack.Pop();
        }
        catch(Exception e)
        {
            Debug.Log(e.Message);
        }

        MyQueue<int> queue = new MyQueue<int>();

        queue.Enqueue(1);
        queue.Enqueue(2);
        queue.Enqueue(3);
        queue.Enqueue(4);
        queue.Enqueue(5);
        queue.Enqueue(6);
        
        while(queue.Count > 0)
        {
            int result = queue.Dequeue();
            Debug.Log(result);
        }
    }
}

 

 

MyQueue 스크립트에서도 마찬가지로 if, else 문으로 else에 throw~를 넣는다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class MyQueue<T> : MonoBehaviour
{
    List<T> values = new List<T>();

    public int Count { get { return values.Count; } }

    public void Enqueue(T value)
    {
        values.Add(value);
    }

    public T Dequeue()
    {
        if(values.Count > 0)
        {
            int idx = 0;
            T result = values[idx]; //첫 번째 값이 불러와진다.
            values.RemoveAt(idx);
            return result;
        }
        else
        {
            throw new InvalidOperationException("MyQueue Empty");
        }
    }
}

 

 


 

 

배열

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoreOnArray : MonoBehaviour
{
    // 점수가 60 이상인지 확인하는 함수
    bool CheckPassed(int score)
    {
        return score >= 60;
    }

    // 값을 출력하는 함수
    void Print(int value)
    {
        Debug.Log($"{value}");
    }

    void Start()
    {
        // 정수형 배열 생성 및 초기화
        int[] scores = new int[] { 80, 74, 81, 90, 34 };

        // 배열의 각 요소를 출력
        foreach (int score in scores)
        {
            Debug.Log($"Original Scores: {score}");
        }

        Debug.Log("- - -");

        // 배열을 정렬하고 정렬된 배열 출력
        Array.Sort(scores);
        Array.ForEach<int>(scores, new Action<int>(Print));
        // Sorted Scores: 34 74 80 81 90

        Debug.Log("- - -");

        // 배열의 차원 수 출력
        Debug.Log($"Number of dimensions: {scores.Rank}");
        // Number of dimensions: 1

        // 이진 검색을 통해 값 81이 배열에서 위치를 출력
        Debug.Log($"Binary search : 81 is at " + $"{Array.BinarySearch<int>(scores, 81)}");
        // Binary search : 81 is at 3

        // 선형 검색을 통해 값 81이 배열에서 위치를 출력
        Debug.Log($"Linear search : 81 is at " + $"{Array.IndexOf(scores, 81)}");
        // Linear search : 81 is at 2

        // 모든 요소가 특정 조건을 만족하는지 확인
        Debug.Log($"Everyone passed ? : " + $"{Array.TrueForAll<int>(scores, CheckPassed)}");
        // Everyone passed ? : False

        // 특정 조건을 만족하는 첫 번째 요소의 인덱스 찾기
        int index = Array.FindIndex<int>(scores, (score) => score < 60);

        // 해당 인덱스의 값을 변경하여 모든 요소가 특정 조건을 만족하는지 확인
        scores[index] = 61;
        Debug.Log($"Everyone passed ? : " + $"{Array.TrueForAll<int>(scores, CheckPassed)}");
        // Everyone passed ? : True

        // 배열의 길이 출력
        Debug.Log($"Old length of scores : " + $"{scores.GetLength(0)}");
        // Old length of scores : 5

        // 배열 크기 조정 및 조정된 크기 출력
        Array.Resize<int>(ref scores, 10);
        Debug.Log($"New length of scores : {scores.Length}");
        // New length of scores : 10

        // 배열의 모든 요소 출력
        Array.ForEach<int>(scores, new Action<int>(Print));
        // Resized Scores: 61 0 0 0 0 0 0 0 0 0

        // 배열의 일부 요소를 지우고 나머지 요소 출력
        Array.Clear(scores, 3, 7);
        Array.ForEach(scores, new Action<int>(Print));
        // Cleared Scores: 61 0 0 0 0 0 0 0 0 0

        // 배열의 일부를 새로운 배열로 복사하고 복사된 배열 출력
        int[] sliced = new int[3];
        Array.Copy(scores, 0, sliced, 0, 3);
        Array.ForEach<int>(sliced, new Action<int>(Print));
        // Sliced Scores: 61 0 0
    }
}

 

 


 

 

배열 정렬하기 -버블 정렬

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ArraySort : MonoBehaviour
{
    void Print(int value)
    {
        Debug.Log($"{value}");
    }
    void Start()
    {
        int[] scores = { 10, 30, 60, 20, 80, 50, 90, 70, 40, 35 };
        int[] newScore = MySort(scores);
    }

    int[] MySort(int[] scores)
    {
        int temp;
        for(int i = 0; i < scores.Length; i++)
        {
            for (int j = 0; j < scores.Length - 1; j++)
            {
                if (scores[j] < scores[j+1])
                {
                    temp = scores[j];
                    scores[j] = scores[j+1];
                    scores[j+1] = temp;
                }
            }
        }
        return scores;
    }
}

 

 

배열 정렬하기 -이진 탐색(Binary Search)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ArraySort : MonoBehaviour
{
    void Print(int value)
    {
        Debug.Log($"{value}");
    }
    void Start()
    {
        int[] scores = { 10, 30, 60, 20, 80, 50, 90, 70, 40, 35 };
        int[] newScore = MySort(scores);

        Array.ForEach<int>(scores, new Action<int>(Print));

        int result = MyBinarySearch(newScore, 70);

        Debug.Log($"70은 {result + 1}번째에 위치");
    }

    int MyBinarySearch(int[] scores, int findValue)
    {
        int low = 0;
        int high = scores.Length - 1;

        while (low <= high)
        {
            int middle = (low + high) / 2;

            // 중간 값이 찾는 값과 같으면 인덱스 반환
            if (scores[middle] == findValue)
                return middle;

            // 중간 값이 찾는 값보다 작으면 오른쪽 부분 검색
            if (scores[middle] < findValue)
                low = middle + 1;
            // 중간 값이 찾는 값보다 크면 왼쪽 부분 검색
            else
                high = middle - 1;
        }

        // 찾는 값이 배열에 없을 경우 0 반환
        return 0;
    }

    int[] MySort(int[] scores)
    {
        int temp;
        for (int i = 0; i < scores.Length; i++)
        {
            for (int j = 0; j < scores.Length - 1; j++)
            {
                if (scores[j] > scores[j + 1])
                {
                    temp = scores[j];
                    scores[j] = scores[j + 1];
                    scores[j + 1] = temp;
                }
            }
        }
        return scores;
    }
}

 

 

이진 탐색 예제2

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

class Person
{
    public string Name { get; private set; }
    public int Age {  get; private set; }
    public string Id { get; private set; }

    public Person(string name, int age, string id)
    {
        this.Name = name;
        this.Age = age;
        this.Id = id;
    }
}

public class ArraySort : MonoBehaviour
{
    void Start()
    {
        Person p1 = new Person("홍길동", 23, "001");
        Person p2 = new Person("김길동", 33, "002");
        Person p3 = new Person("최길동", 31, "003");
        Person p4 = new Person("고길동", 28, "004");
        Person p5 = new Person("마길동", 27, "005");
        Person p6 = new Person("박길동", 36, "006");
        Person p7 = new Person("우길동", 42, "007");

        List<Person> list = new List<Person> { p1, p2, p3, p4, p5, p6, p7 };
    }

    int binaryAgeSearch(Person[] persons, int age)
    {
        int low = 0, high = persons.Length - 1;
        int mid;

        while(low <= high)
        {
            mid = (low + high) / 2;

            if (persons[mid].Age == age)
            {
                return mid;
            }
            else if (persons[mid].Age > age)
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }
        return -1;
    }
}

 

 

이진 탐색 예제3 -나이로 검색하기

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

class Person : IComparable<Person> //인터페이스 추가
{
    public string Name { get; private set; }
    public int Age {  get; private set; }
    public string Id { get; private set; }

    public Person(string name, int age, string id)
    {
        this.Name = name;
        this.Age = age;
        this.Id = id;
    }

    public int CompareTo(Person other) //"Ctrl + ."으로 자동 완성
    {
        if(other == null) return 1;
        else return this.Age.CompareTo(other.Age);
    }
}

public class ArraySort : MonoBehaviour
{
    void Start()
    {
        Person p1 = new Person("홍길동", 23, "001");
        Person p2 = new Person("김길동", 33, "002");
        Person p3 = new Person("최길동", 31, "003");
        Person p4 = new Person("고길동", 28, "004");
        Person p5 = new Person("마길동", 27, "005");
        Person p6 = new Person("박길동", 36, "006");
        Person p7 = new Person("우길동", 42, "007");

        List<Person> list = new List<Person> { p1, p2, p3, p4, p5, p6, p7 };

        list.Sort();

        int result = binaryAgeSearch(list.ToArray(), 36); //괄호 안에 찾고자 하는 정보

        Debug.Log(result);
    }

    int binaryAgeSearch(Person[] persons, int age)
    {
        int low = 0, high = persons.Length - 1;
        int mid;

        while(low <= high)
        {
            mid = (low + high) / 2;

            if (persons[mid].Age == age)
            {
                return mid;
            }
            else if (persons[mid].Age > age)
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }
        return -1;
    }
}

 

 

이진 탐색 예제3 -이름으로 검색하기

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

class Person : IComparable<Person> //인터페이스 추가
{
    public string Name { get; private set; }
    public int Age {  get; private set; }
    public string Id { get; private set; }

    public Person(string name, int age, string id)
    {
        this.Name = name;
        this.Age = age;
        this.Id = id;
    }

    public int CompareTo(Person other) //"Ctrl + ."으로 자동 완성
    {
        if(other == null) return 1;
        else return this.Age.CompareTo(other.Age);
    }
}

public class ArraySort : MonoBehaviour
{
    void Start()
    {
        Person p1 = new Person("홍길동", 23, "001");
        Person p2 = new Person("김길동", 33, "002");
        Person p3 = new Person("최길동", 31, "003");
        Person p4 = new Person("고길동", 28, "004");
        Person p5 = new Person("마길동", 27, "005");
        Person p6 = new Person("박길동", 36, "006");
        Person p7 = new Person("우길동", 42, "007");

        List<Person> list = new List<Person> { p1, p2, p3, p4, p5, p6, p7 };

        list.Sort(); //정렬

        int result = binaryAgeSearch(list.ToArray(), 36); //괄호 안에 찾고자 하는 정보 검색

        list.Sort(new Comparison<Person>((n1, n2) => n1.Name.CompareTo(n2.Name))); //정렬. n1의 이름과 n2의 이름 비교

        int result2 = binaryNameSeach(list.ToArray(), "우길동", 0, list.ToArray().Length - 1);

        Person p8 = new Person("윤길동", 34, "008"); //새로운 값 생성

        if (p6.Equals(p7))
        {
            Debug.Log("");
        }
    }

    int binaryAgeSearch(Person[] persons, int age) //나이로 정렬
    {
        int low = 0, high = persons.Length - 1;
        int mid;

        while(low <= high)
        {
            mid = (low + high) / 2;

            if (persons[mid].Age == age)
            {
                return mid;
            }
            else if (persons[mid].Age > age)
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }
        return -1;
    }

    int binaryNameSeach(Person[] persons, string name, int myLow, int myHigh) //이름으로 정렬
    {
        if (myLow > myHigh) return -1;
        if (name == null) return -1;

        int mid = myLow + (myHigh - myLow) / 2;

        if (persons[mid].Name.CompareTo(name) == 0)
        {
            return mid;
        }
        else if (persons[mid].Name.CompareTo(name) > 0)
        {
            myHigh = mid - 1;
            return binaryNameSeach(persons, name, myLow, myHigh); //재귀 함수
        }
        else
        {
            myLow = mid + 1;
            return binaryNameSeach(persons, name, myLow, myHigh); //재귀 함수
        }
    }
}

int binaryNameSearch를 추가 하여 이름으로 정렬하고 검색하는 기능이 추가되었다.

728x90
반응형