리스트와 링크드 리스트

리스트 ( List )

 

 

  • 데이터를 순서대로 저장하는 선형 자료구조
  • 인덱스 기반으로 각 요소에 접근 가능
  • 일반 배열과 다르게 요소가 추가되어 공간이 부족해지면 자동으로 더 큰 배열을 새로 할당해 기존 요소를 복사함
  • 중간 삽입/삭제가 일어나면 ,연속성을 유지하기 위해 연산 부하가 생김 > 삽입/삭제가 된 부분 뒤 요소를 전부 복사해서 땡겨오거나 밀어서 다시 배열을 만드는 방식
  • 배열의 크기는 Capacity로 실제 요소의 수는 Count로 알 수 있음

 

 

 

주요 특징 및 성능

연산 시간 복잡도 설명
요소 접근 (Access) O(1)
인덱스를 알면 주소를 바로 계산할 수 있어 매우 빠릅니다.
끝에 삽입/삭제 O(1) (평균)
끝에 추가하는 것은 보통 빠르지만, 배열 크기를 늘려야 할 경우 $O(N)$이 될 수 있습니다.
중간에 삽입/삭제 O(N)
요소를 삽입하거나 삭제할 때, 그 뒤의 모든 요소를 한 칸씩 밀거나 당겨야 하므로 느립니다.
메모리 효율적
연속된 공간에 저장되어 메모리 참조 효율(캐시 활용)이 높습니다.

 

 

 

 

자주 사용하는 메서드

 

 

1. 요소 추가 및 삽입 (Add & Insert)

메서드 설명 예시 (List<int> numbers)
Add(T item) 리스트의 맨 끝에 요소를 추가합니다. numbers.Add(10); // [10]
AddRange(IEnumerable<T> collection) 다른 컬렉션(배열, 다른 리스트 등)의 모든 요소를 리스트의 맨 끝에 추가합니다. numbers.AddRange(new[] { 20, 30 }); // [10, 20, 30]
Insert(int index, T item) 지정된 인덱스 위치에 요소를 삽입하고, 기존 요소들을 뒤로 밉니다. numbers.Insert(1, 15); // [10, 15, 20, 30]
 

2. 요소 검색 및 확인 (Search & Check)

메서드 설명 예시 (List<int> numbers)
Contains(T item) 리스트에 특정 요소가 포함되어 있는지 확인하고, bool 값을 반환합니다. bool has20 = numbers.Contains(20); // true
IndexOf(T item) 특정 요소의 첫 번째로 발견되는 인덱스를 반환합니다. 요소가 없으면 -1을 반환합니다. int index = numbers.IndexOf(15); // 1
Count (속성) 리스트에 포함된 요소의 개수를 반환합니다. int count = numbers.Count; // 4
 

 

3. 요소 삭제 (Remove)

메서드 설명 예시 (List<int> numbers = [10, 15, 20, 30])
Remove(T item) 지정된 요소와 일치하는 첫 번째 항목을 찾아 삭제합니다. 성공하면 true를 반환합니다. numbers.Remove(15); // [10, 20, 30]
RemoveAt(int index) 지정된 인덱스 위치의 요소를 삭제합니다. numbers.RemoveAt(0); // [20, 30]
RemoveAll(Predicate<T> match) 지정된 **조건(Predicate)**에 맞는 모든 요소를 제거합니다. 제거된 요소의 개수를 반환합니다. numbers.RemoveAll(x => x > 25); // 1개 제거, [20]
Clear() 리스트의 모든 요소를 제거하여 빈 리스트로 만듭니다. numbers.Clear(); // []
 

4. 기타 유용한 메서드 (Utility)

메서드 설명 예시 (List<int> numbers = [30, 10, 20])
Sort() 리스트의 요소들을 오름차순으로 정렬합니다. numbers.Sort(); // [10, 20, 30]
Reverse() 리스트의 요소 순서를 반대로 뒤집습니다. numbers.Reverse(); // [20, 10, 30]
ToArray() 리스트의 모든 요소를 포함하는 새로운 배열을 만듭니다. int[] arr = numbers.ToArray();
Find(Predicate<T> match) 지정된 조건(Predicate)에 맞는 첫 번째 요소를 찾아 반환합니다. 없으면 기본값(참조 타입은 null)을 반환합니다. int firstOdd = numbers.Find(x => x % 2 != 0);
FindAll(Predicate<T> match) 지정된 조건에 맞는 모든 요소를 포함하는 새로운 리스트를 반환합니다. List<int> evens = numbers.FindAll(x => x % 2 == 0);

링크드 리스트 ( Linked List )

 

 

  • 선형이 아닌 데이터 노드들이 메모리의 여기저기 흩어져 저장됩니다
  • 노드가 앞, 뒤 노드의 주소를 기억해서 삽입 삭제가 일어나면 그 주소들만 연결시켜주면 되는 구조입니디, 리스트처럼 전체복사 안해도 됨
  • 삽입/삭제가 자주 일어나느 파일 형식에 유리
  • 단점은 원하는 요소를 찾기 위해서는 한번 전체적으로 주소를 타고타고 돌아줘야 찾을 수 있습니다

 

 

 

주요 특징 및 성능

연산 시간 복잡도 설명
요소 접근 (Access) 특정 인덱스의 요소를 찾으려면 처음부터 순차적으로 노드를 따라가야 하므로 느립니다.
삽입/삭제 삽입/삭제 위치를 이미 알고 있다면, 노드의 주소(링크)만 변경하면 되므로 매우 빠릅니다.
중간에 삽입/삭제 삽입/삭제할 위치를 찾기 위해 $O(N)$이 필요하고, 실제 작업은 $O(1)$입니다. (위치 찾기 과정이 지배적)
메모리 비효율적 각 요소를 저장할 때 데이터 외에 다음 노드를 가리키는 추가적인 포인터 공간이 필요합니다.
 
 
 
 
 

자주 사용하는 메서드

 

1. 노드 생성 및 참조

메서드/속성 설명 예시 (LinkedList<int> list)
First (속성) 리스트의 첫 번째 노드를 반환합니다. 노드가 없으면 null을 반환합니다. var firstNode = list.First;
Last (속성) 리스트의 마지막 노드를 반환합니다. 노드가 없으면 null을 반환합니다. var lastNode = list.Last;
Find(T value) 지정된 값을 가진 첫 번째 노드를 찾아 반환합니다. 못 찾으면 null을 반환합니다. var node = list.Find(10);
 

2. 요소 삽입 (Add)

삽입 메서드는 대부분 $O(1)$의 시간 복잡도를 가집니다.

메서드 설명 예시 (LinkedList<int> list)
AddFirst(T value) 리스트의 맨 앞에 새 노드를 삽입합니다. list.AddFirst(10); // [10]
AddLast(T value) 리스트의 맨 뒤에 새 노드를 삽입합니다. list.AddLast(20); // [10, 20]
AddBefore(LinkedListNode<T> node, T value) 지정된 노드 바로 앞에 새 노드를 삽입합니다. var node20 = list.Find(20); list.AddBefore(node20, 15); // [10, 15, 20]
AddAfter(LinkedListNode<T> node, T value) 지정된 노드 바로 뒤에 새 노드를 삽입합니다. var node10 = list.First; list.AddAfter(node10, 12); // [10, 12, 15, 20]
 

3. 요소 삭제 (Remove)

삭제 메서드 역시 대부분 $O(1)$의 시간 복잡도를 가집니다.

메서드 설명 예시 (LinkedList<int> list = [10, 12, 15, 20])
Remove(T value) 지정된 을 가진 첫 번째 노드를 삭제합니다. 성공하면 true를 반환합니다. list.Remove(12); // [10, 15, 20]
Remove(LinkedListNode<T> node) 지정된 노드를 리스트에서 삭제합니다. var node15 = list.Find(15); list.Remove(node15); // [10, 20]
RemoveFirst() 리스트의 첫 번째 노드를 삭제합니다. list.RemoveFirst(); // [20]
RemoveLast() 리스트의 마지막 노드를 삭제합니다. list.RemoveLast(); // []
Clear() 리스트의 모든 요소를 제거하여 빈 리스트로 만듭니다. list.Clear();
 

4. 기타 속성

속성 설명
Count 리스트에 포함된 노드의 개수를 반환합니다.
Contains(T value) 리스트에 특정 값이 포함되어 있는지 확인하고, bool 값을 반환합니다. (주의: 이 메서드는 전체 순회하므로 $O(N)$입니다.)

리스트와 링크드 리스트 차이

특징 리스트 (List / 동적 배열)
링크드 리스트 (Linked List)
데이터 저장 방식 연속된 메모리 공간
비연속적인 메모리, 노드로 연결
접근 성능 빠름 (O(1)) - 인덱스 사용
느림 (O(N)) - 순차적 탐색 필요
삽입/삭제 성능 느림 (O(N)) - 중간일 경우
빠름 (O(1)) - 링크만 변경 (위치를 알고 있다면)
메모리 오버헤드 적음 - 포인터 공간 불필요
많음 - 모든 노드에 포인터 공간 필요

 

결론적으로

  • 리스트는 데이터 접근(읽기,쓰기) 하는 작업이 많고 , 삽입/삭제가 적을 때 유리
  • 링크드 리스트는 데이터의 삽입/삭제 가 번번히 일어나고 접근이 덜 중요할 때 유리

'C# > 자료구조를 활용한 데이터 관리' 카테고리의 다른 글

그래프 와 트리  (0) 2025.11.03
딕셔너리  (0) 2025.11.03
스택과 큐  (0) 2025.11.03
자료구조  (0) 2025.10.14