언제 List 대 LinkedList 를 사용하는 것이 더 낫 습니까?
답변
편집하다
이 답변에 대한 의견을 읽으십시오. 사람들은 내가 적절한 테스트를하지 않았다고 주장합니다. 나는 이것이 받아 들여서는 안된다는 데 동의합니다. 배우면서 몇 가지 테스트를 수행하고 공유하는 느낌이 들었습니다.
원래 답변 …
흥미로운 결과를 찾았습니다.
// Temporary class to show the example
class Temp
{
public decimal A, B, C, D;
public Temp(decimal a, decimal b, decimal c, decimal d)
{
A = a; B = b; C = c; D = d;
}
}
연결된 목록 (3.9 초)
LinkedList<Temp> list = new LinkedList<Temp>();
for (var i = 0; i < 12345678; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
목록 (2.4 초)
List<Temp> list = new List<Temp>(); // 2.4 seconds
for (var i = 0; i < 12345678; i++)
{
var a = new Temp(i, i, i, i);
list.Add(a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
본질적으로 데이터에만 액세스하더라도 훨씬 느립니다 !! 나는 linkedList를 사용하지 않는다고 말한다.
다음은 많은 인서트를 수행하는 또 다른 비교입니다 (목록 중간에 항목을 삽입 할 계획입니다)
연결 목록 (51 초)
LinkedList<Temp> list = new LinkedList<Temp>();
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
var curNode = list.First;
for (var k = 0; k < i/2; k++) // In order to insert a node at the middle of the list we need to find it
curNode = curNode.Next;
list.AddAfter(curNode, a); // Insert it after
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
목록 (7.26 초)
List<Temp> list = new List<Temp>();
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.Insert(i / 2, a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
삽입 할 위치에 대한 참조가있는 링크 된 목록 (.04 초)
list.AddLast(new Temp(1,1,1,1));
var referenceNode = list.First;
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
list.AddBefore(referenceNode, a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
그래서 단지 당신이 여러 항목을 삽입 계획하고있는 경우 도 어딘가에는 다음 링크 된 목록을 사용하여 항목을 삽입 할 계획 곳의 레퍼런스를 가지고있다. 많은 항목을 삽입해야하기 때문에 삽입하려는 위치를 검색하면 시간이 걸리기 때문에 더 빠르지 않습니다.
답변
대부분의 경우 List<T>
더 유용합니다. LinkedList<T>
목록 중간에 항목을 추가 / 제거 할 때 비용이 적게 드는 반면 목록 끝에List<T>
값을 추가 / 제거 할 수 있습니다 .
LinkedList<T>
순차 또는 역순으로 순차 데이터에 액세스하는 경우에만 가장 효율적입니다. 랜덤 액세스는 매번 체인을 걸어야하기 때문에 상대적으로 비용이 많이 듭니다 (따라서 인덱서가없는 이유). 그러나 a List<T>
는 본질적으로 배열 (래퍼 포함)이므로 임의 액세스가 좋습니다.
List<T>
또한 지원 방법을 많이 제공합니다 – Find
, ToArray
등; 그러나 LinkedList<T>
확장 방법을 통해 .NET 3.5 / C # 3.0 에서도 사용할 수 있으므로 그다지 중요하지 않습니다.
답변
연결된 목록을 목록으로 생각하는 것은 약간 오해의 소지가 있습니다. 체인과 비슷합니다. 실제로 .NET에서는 LinkedList<T>
조차 구현하지 않습니다 IList<T>
. 비록 링크 된리스트에는 인덱스의 실제 개념이 없지만, 비록 존재하는 것처럼 보일 수 있습니다. 클래스에 제공된 메소드 중 어느 것도 인덱스를 허용하지 않습니다.
연결된 목록은 단독으로 연결되거나 이중으로 연결될 수 있습니다. 이것은 체인의 각 요소가 다음 요소에만 링크되는지 (단일 링크 됨) 또는 이전 / 다음 요소 모두에 링크가 있는지 (두 개 링크 됨)를 나타냅니다. LinkedList<T>
이중 연결되어 있습니다.
내부적 List<T>
으로 배열이 지원합니다. 이것은 메모리에서 매우 컴팩트 한 표현을 제공합니다. 반대로, LinkedList<T>
연속 요소 사이의 양방향 링크를 저장하기위한 추가 메모리가 필요합니다. 따라서 a의 메모리 풋 프린트 LinkedList<T>
는 일반적으로 메모리 용량 보다 더 클 것입니다 List<T>
( List<T>
추가 작업 중 성능을 향상시키기 위해 사용되지 않는 내부 배열 요소를 가질 수 있는 경고가 있음 ).
성능 특성도 다릅니다.
추가
LinkedList<T>.AddLast(item)
일정한 시간List<T>.Add(item)
상각 일정 시간, 선형 최악의 경우
접두사
LinkedList<T>.AddFirst(item)
일정한 시간List<T>.Insert(0, item)
선형 시간
삽입
LinkedList<T>.AddBefore(node, item)
일정한 시간LinkedList<T>.AddAfter(node, item)
일정한 시간List<T>.Insert(index, item)
선형 시간
제거
LinkedList<T>.Remove(item)
선형 시간LinkedList<T>.Remove(node)
일정한 시간List<T>.Remove(item)
선형 시간List<T>.RemoveAt(index)
선형 시간
카운트
LinkedList<T>.Count
일정한 시간List<T>.Count
일정한 시간
포함
LinkedList<T>.Contains(item)
선형 시간List<T>.Contains(item)
선형 시간
명확한
LinkedList<T>.Clear()
선형 시간List<T>.Clear()
선형 시간
보다시피, 그것들은 대부분 동등합니다. 실제로 API는 사용하기 LinkedList<T>
가 더 번거로우 며 내부 요구 사항에 대한 세부 정보가 코드에 유출됩니다.
그러나 목록 내에서 많은 삽입 / 제거를 수행해야하는 경우 일정한 시간을 제공합니다. List<T>
삽입 / 제거 후 목록의 추가 항목을 뒤섞어 야하므로 선형 시간을 제공합니다.
답변
연결된 목록은 목록 구성원을 매우 빠르게 삽입하거나 삭제합니다. 링크 된 목록의 각 멤버에는 목록의 다음 멤버에 대한 포인터가 포함되어 i 위치에 멤버를 삽입합니다.
- i-1 멤버의 포인터를 업데이트하여 새 멤버를 가리 킵니다.
- 새 멤버의 포인터를 멤버 i를 가리 키도록 설정하십시오.
연결된 목록의 단점은 임의 액세스가 불가능하다는 것입니다. 멤버에 액세스하려면 원하는 멤버를 찾을 때까지 목록을 탐색해야합니다.
답변
내 이전 답변이 충분히 정확하지 않았습니다. 정말 끔찍했습니다 : D 그러나 지금은 훨씬 더 유용하고 정확한 답변을 게시 할 수 있습니다.
추가 테스트를했습니다. https://github.com/ukushu/DataStructuresTestsAndOther.git 링크를 통해 소스를 찾아 환경에서 다시 확인할 수 있습니다.
짧은 결과 :
-
배열은 다음을 사용해야합니다.
- 가능한 자주. 동일한 양의 정보를 얻기 위해 빠르며 RAM 범위가 가장 작습니다.
- 필요한 정확한 세포 수를 알고 있다면
- 배열 <85000b에 저장된 데이터 (정수 데이터의 경우 85000/32 = 2656 요소)
- 높은 랜덤 액세스 속도가 필요한 경우
-
목록을 사용해야합니다.
- 목록 끝에 셀을 추가해야하는 경우 (종종)
- 목록의 시작 / 중간에 셀을 추가해야하는 경우
- 배열 <85000b에 저장된 데이터 (정수 데이터의 경우 85000/32 = 2656 요소)
- 높은 랜덤 액세스 속도가 필요한 경우
-
LinkedList는 다음을 사용해야합니다.
- 목록의 시작 / 중간 / 끝에 셀을 추가해야하는 경우 (종종)
- 순차적 액세스 만 필요한 경우 (앞으로 / 뒤로)
- 큰 항목을 저장해야하지만 항목 수가 적은 경우
- 링크에 추가 메모리를 사용하므로 대량의 항목에는 사용하지 않는 것이 좋습니다.
자세한 내용은:
-
LinkedList<T>
internally는 .NET의 List가 아닙니다. 심지어 구현하지도 않습니다IList<T>
. 이것이 인덱스와 관련된 인덱스와 메소드가없는 이유입니다. -
LinkedList<T>
노드 포인터 기반 컬렉션입니다. .NET에서는 이중 링크 구현입니다. 이는 이전 / 다음 요소가 현재 요소에 연결되어 있음을 의미합니다. 또한 데이터가 조각화되어 다른 RAM의 다른 위치에 다른 목록 개체를 배치 할 수 있습니다. 또한LinkedList<T>
forList<T>
또는 Array 보다 더 많은 메모리가 사용됩니다 . -
List<T>
.Net에서 Java의 대안입니다ArrayList<T>
. 이것은 이것이 배열 래퍼임을 의미합니다. 따라서 하나의 연속 된 데이터 블록으로 메모리에 할당됩니다. 할당 된 데이터 크기가 85000 바이트를 초과하면 Large Object Heap으로 이동합니다. 크기에 따라 힙 조각화 (가벼운 형태의 메모리 누수)가 발생할 수 있습니다. 그러나 크기가 85000 바이트 미만인 경우 메모리에서 매우 작고 빠른 액세스 표현을 제공합니다. -
랜덤 액세스 성능과 메모리 소비에는 단일 연속 블록이 선호되지만 정기적으로 크기를 변경해야하는 컬렉션의 경우 일반적으로 Array와 같은 구조를 새 위치로 복사해야하지만 연결된 목록은 새로 삽입 된 메모리 만 관리하면됩니다. / 삭제 된 노드.
답변
List와 LinkedList의 차이점은 기본 구현에 있습니다. List는 배열 기반 컬렉션 (ArrayList)입니다. LinkedList는 노드 포인터 기반 콜렉션 (LinkedListNode)입니다. API 레벨 사용법에서 ICollection, IEnumerable 등과 같은 동일한 인터페이스 세트를 구현하므로 둘 다 거의 동일합니다.
중요한 차이점은 성능이 중요합니다. 예를 들어, “INSERT”작업이 많은 목록을 구현하는 경우 LinkedList가 List보다 성능이 우수합니다. LinkedList는 O (1) 시간에이를 수행 할 수 있지만 List는 기본 배열의 크기를 확장해야 할 수도 있습니다. 자세한 정보 / 세부 사항은 LinkedList와 배열 데이터 구조의 알고리즘 차이를 읽으십시오. http://en.wikipedia.org/wiki/Linked_list 및 배열
이 도움을 바랍니다.
답변
배열에 대한 링크 된 목록의 주요 장점은 링크가 항목을 효율적으로 재 배열 할 수있는 기능을 제공한다는 것입니다. 세지윅, p. 91