C# 컬렉션 (Feat. List와 Array 성능 비교)

김민구·2024년 12월 11일
0

C#

목록 보기
10/31

컬렉션(collection)이란, 같은 성격을 띠는 데이터의 모음을 담는 자료 구조.

위의 설명에서 컬렉션만 배열로 한번 바꿔 보면 배열 설명과 정의가 같다.
즉 배열도 .NET 프레임워크가 제공하는 다양한 컬렉션 자료 구조의 일부

  1. List
    특징: 순서가 보장되는 데이터의 집합. 인덱스를 통해 요소에 접근 가능.
    주요 용도 : 데이터를 순서대로 저장하고, 특정 인덱스의 값을 빠르게 조회해야 할 때 사용.
    예시 : 순서대로 정렬된 값을 저장
    기타 : ArrayList: C# 2.0 이전에 사용되던 비제네릭 컬렉션으로, 성능이 좋지 않고, 요소의 타입이 박싱/언박싱되어야 하므로 요즘 C#에서는 List를 사용하는 것이 좋다.
  • 예제 코드
internal class Program
{
    private static void Main(string[] args)
    {
        // List 예제
        List<string> names = new List<string> { "Ace", "Base", "Car" };

        for (int i = 0; i < names.Count; i++)
        {
            Console.Write(names[i]);
            Console.WriteLine();
        }

        names.Add("Delete");

        for (int i = 0; i < names.Count; i++)
        {
            Console.Write(names[i]);
            Console.WriteLine();
        }

        names.Remove("Base");

        foreach (string name in names) 
        {
            Console.Write(name);
            Console.WriteLine();
        }

        names.Sort();

        foreach (string name in names)
        {
            Console.Write(name);
            Console.WriteLine();
        }

        names.Reverse();
        foreach (string name in names)
        {
            Console.Write(name);
            Console.WriteLine();
        }
        Console.WriteLine(names.IndexOf("Ace"));
        Console.WriteLine(names.IndexOf("Base"));
        Console.WriteLine(names.IndexOf("Delete"));

        names.Clear();

        foreach (string name in names)
        {
            Console.Write(name);
        }

        Console.WriteLine("비었다");

    }
}
  1. Dictionary<Key, Value>
    특징: 키와 값 쌍으로 데이터를 저장. 키를 통해 값에 빠르게 접근 가능.
    주요 용도: 데이터를 키와 값으로 묶어 관리해야 할 때 사용.
    예시: 학생의 번호를 키로, 학생의 이름을 값으로 저장

예제 코드

internal class Program
{
    private static void Main(string[] args)
    {
        // Dictionary 예제
        Dictionary<int, string> students = new Dictionary<int, string>();
        students.Add(1, "Alice");
        students.Add(2, "Bob");

        students.Remove(1);

        foreach (var student in students)
        {
            Console.WriteLine(student);
        }

        students.Add(3, "Chuk");

        foreach (var student in students)
        {
            Console.WriteLine(student);
        }

        students.Clear();

        foreach (var student in students)
        {
            Console.WriteLine(student);
        }

    }
}
  1. HashSet
    특징: 중복된 값을 허용하지 않는 집합. 요소의 존재 여부를 빠르게 확인 가능.
    주요 용도: 중복된 데이터를 제거하고, 특정 요소가 집합에 포함되어 있는지 확인해야 할 때 사용.
    예시: 로또 번호와 같은 중복되지 않는 값들을 저장

예제 코드

internal class Program
{
    private static void Main(string[] args)
    {
        // HashSet 예제
        HashSet<int> lottoNumbers = new HashSet<int> { 1, 1, 5, 10, 23, 25, 45 };

        foreach (int i in lottoNumbers)
        {
            Console.WriteLine(i);
        }

        lottoNumbers.Remove(1);

        foreach (int i in lottoNumbers)
        {
            Console.WriteLine(i);
        }
    }
}
  1. Queue
    특징: FIFO(First In First Out) 방식으로 데이터를 관리. 먼저 들어온 데이터가 먼저 나감.
    주요 용도: 작업 순서를 유지해야 할 때 사용.
    예시: 프린터 작업 대기열

예제 코드

internal class Program
{
    private static void Main(string[] args)
    {
        // Queue<T> 생성 (T는 저장할 데이터의 타입)
        Queue<string> myQueue = new Queue<string>();

        // 큐에 데이터 추가 (Enqueue)
        myQueue.Enqueue("apple");
        myQueue.Enqueue("banana");
        myQueue.Enqueue("cherry");

        // 큐에서 데이터 꺼내기 (Dequeue)
        while (myQueue.Count > 0)
        {
            Console.WriteLine(myQueue.Dequeue());
        }
    }
}
  1. Stack
    특징: LIFO(Last In First Out) 방식으로 데이터를 관리. 나중에 들어온 데이터가 먼저 나감.
    주요 용도: 함수 호출 스택, 되돌리기 기능 등에 사용.
    예시: 웹 브라우저의 히스토리

예제 코드

 // Stack<T> 생성 (T는 저장할 데이터의 타입)
            Stack<string> myStack = new Stack<string>();

            // 스택에 데이터 추가 (Push)
            myStack.Push("apple");
            myStack.Push("banana");
            myStack.Push("cherry");

            // 스택에서 데이터 꺼내기 (Pop)
            while (myStack.Count > 0)
            {
                Console.WriteLine(myStack.Pop());
            }
  1. SortedList<Key, Value>
    특징: 키를 기준으로 정렬된 Dictionary.
    주요 용도: 데이터를 키 값으로 정렬하여 관리해야 할 때 사용.
    예시: 단어 사전

예제 코드

// SortedList<TKey, TValue> 생성
SortedList<int, string> scores = new SortedList<int, string>();

// 데이터 추가
scores.Add(85, "홍길동");
scores.Add(92, "김철수");
scores.Add(78, "박영희");

// 정렬된 순서로 출력
foreach (var item in scores)
{
    Console.WriteLine("점수: {0}, 이름: {1}", item.Key, item.Value);
}
  1. LinkedList
    특징: 노드 간의 연결 관계를 통해 데이터를 저장. 중간에 노드를 삽입하거나 삭제하는 것이 효율적.
    주요 용도: 데이터의 삽입, 삭제가 빈번하게 일어나는 경우에 사용.
    예시: 음악 재생 목록

예제 코드

        // LinkedList<T> 생성
        LinkedList<int> numbers = new LinkedList<int>();

        // 데이터 추가 (AddLast)
        numbers.AddLast(10);
        numbers.AddLast(20);
        numbers.AddLast(30);

        // 데이터 출력
        foreach (int number in numbers)
        {
            Console.WriteLine(number);
        }

        numbers.Remove(20);

        // 데이터 출력
        foreach (int number in numbers)
        {
            Console.WriteLine(number);
        }

Feat. List와 Array의 성능 비교

  1. List에 Add를 호출하는 과정
    ㄴ Add를 호출하면 현재 배열의 사이즈를 확인해 사이즈를 비교하고 가득 찼다고 판단하면 EnsureCapacity 메서드를 호출한다.
    ㄴ EnsureCapacity 메서드는 곽찬 배열에 크기를 2배로 늘린다.
    ㄴ 하나의 데이터를 추가하기 위해 Add를 실행했을 때 배열의 크기를 2배로 늘려 이것이 반복되어 배열이 커질 수록 배가되어 비효율적이다.

  2. List와 Array의 성능 비교
    ㄴ List는 가득 찼을때 EnsureCapacity 메서드로 인해 크기가 2배로 늘어나는데 이런 동적인 특성으로 인해 비연속 적으로 메모리에 할당된다.
    ㄴ Array는 정해진 크기로 인해 연속적으로 메모리 할당 된다.

결론) 즉 List와 Array의 특징으로 인해 연속적으로 메모리에 할당되어 CPU 캐시가 효율적으로 작동하므로 메모리 접근이 더 빠르므로, Array가 더 속도가 빠르다.

profile
C#, Unity

0개의 댓글