리스트(list)는 순서를 갖고 있는 자료구조다. 순차 자료구조엔 선형 리스트가 있고, 연결 자료구조엔 단일 연결 리스트, 원형 연결 리스트, 이중 연결 리스트가 있다. 리스트는 다른 자료구조의 기본이 된다.
리스트는 연산에 대해 아래와 같이 동작해야 한다.
선형 리스트(Linear List)는 순서 리스트(Ordered List)라고도 한다. 순차적으로 구현한 것이기 때문에 임의 접근이 가능하다.
List<int> list = new List<int>();
// # 삽입
// Add()는 리스트의 끝에 데이터를 추가한다.
list.Add(5); // [5]
list.Add(4); // [5][4]
list.Add(3); // [5][4][3]
list.Add(2); // [5][4][3][2]
list.Add(1); // [5][4][3][2][1]
// Insert()는 특정 위치에 데이터를 추가한다.
list.Insert(2, 6); // [5][4][6][3][2][1]
// # 읽기
// 인덱서를 통해 특정 위치의 데이터에 접근할 수 있다.
Console.WriteLine(list[3]); // 3
// # 검색
// Contains()를 통해 데이터의 존재 유무를 확인할 수 있다.
Console.WriteLine(list.Contains(6)); // True
Console.WriteLine(list.Contains(7)); // False
// IndexOf()를 사용하면 데이터가 몇 번째 인덱스에 있는지도 확인할 수 있다.
Console.WriteLine(list.IndexOf(6)); // 2
Console.WriteLine(list.IndexOf(7)); // -1
// # 삭제
// Remove()를 이용하면 특정 데이터를 삭제할 수 있다.
// 중복된 데이터가 있는 경우 첫 번째로 발견된 데이터를 삭제한다.
list.Remove(6); // [5][4][3][2][1]
2
// RemoveAt()은 특정 위치에 존재하는 데이터를 삭제한다.
list.RemoveAt(3); // [5][4][3][1]
연결 리스트는 메모리에 연속적으로 배치되어있지 않아 임의 접근이 불가능하다.
연결 리스트의 종류는 크게 세가지로 나눌 수 있다.
연결 리스트는 이전, 혹은 이후 데이터를 찾기 위한 참조 타입의 변수가 필요하다.
// 연결 리스트를 구성하는 단위를 노드(Node)라고 한다.
class Node<T>
{
public T Data { get; set; }
// 실제 데이터 말고도 리스트를 구성하기 위한 추가 데이터가 필요하다.
public Node Next { get; set; }
public Node Prev { get;
C#은 LinkedListNode로 구현이 되어 있으며, 연결 리스트는 LinkedList다. LinkedList는 이중 연결 리스트로 구현이 되어 있다.
// 리스트를 생성한다.
LinkedList<int> list = new LinkedList<int>();
// # 삽입
// AddLast()는 리스트의 끝에 데이터를 추가한다.
list.AddLast(5); // [5]
list.AddLast(4); // [5][4]
// AddFirst()는 리스트의 처음에 데이터를 추가한다.
list.AddFirst(1); // [1][5][4]
list.AddFirst(2); // [2][1][5][4]
// # 읽기
// First는 연결 리스트의 첫 번째 노드를 가져온다.
LinkedListNode<int> first = list.First; // [2][1][5][4]
// ↑
// Last는 연결 리스트의 마지막 노드를 가져온다.
LinkedListNode<int> last = list.Last; // [2][1][5][4]
// ↑
// Next 혹은 Previous로 포인터를 이동할 수 있다.
LinkedListNode<int> node = first.Next; // [2][1][5][4]
// ↑
// # 삽입
// AddAfter()를 이용하면 노드 다음에 데이터를 추가할 수 있다.
list.AddAfter(first, 10); // [2][10][1][5][4]
// AddBefore()을 이용하면 노드 이전에 데이터를 추가할 수 있다.
list.AddBefore(node, 8); // [2][10][8][1][5][4]
// # 검색
// Contains()를 통해 데이터의 존재 유무를 확인할 수 있다.
Console.WriteLine(list.Contains(10)); // True
Console.WriteLine(list.Contains(13)); // False
// Find()를 통해 데이터를 저장하고 있는 노드를 가져올 수 있다.
// Null일 수 있다.
Console.WriteLine(list.Find(8)?.Value); // 8
// # 삭제
// Remove()를 이용하면 특정 데이터를 삭제할 수 있다.
list.Remove(10); // [2][8][1][5][4]
list.Remove(6); // [2][8][1][5][4]
// 삭제할 노드를 넣어도 된다.
list.Remove(list.Last.Previous); // [2][8][1][4]
연결 리스트의 각 연산에 대한 성능은 아래와 같다.