[C#] 언제 List와 LinkedList를 사용해야합니까?

언제 ListLinkedList 를 사용하는 것이 더 낫 습니까?



답변

편집하다

이 답변에 대한 의견을 읽으십시오. 사람들은 내가 적절한 테스트를하지 않았다고 주장합니다. 나는 이것이 받아 들여서는 안된다는 데 동의합니다. 배우면서 몇 가지 테스트를 수행하고 공유하는 느낌이 들었습니다.

원래 답변 …

흥미로운 결과를 찾았습니다.

// 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는 다음을 사용해야합니다.

    • 목록의 시작 / 중간 / 끝에 셀을 추가해야하는 경우 (종종)
    • 순차적 액세스 만 필요한 경우 (앞으로 / 뒤로)
    • 큰 항목을 저장해야하지만 항목 수가 적은 경우
    • 링크에 추가 메모리를 사용하므로 대량의 항목에는 사용하지 않는 것이 좋습니다.

자세한 내용은:

введите сюда описание изображения
알고 싶은 것 :

  1. LinkedList<T>internally는 .NET의 List가 아닙니다. 심지어 구현하지도 않습니다 IList<T>. 이것이 인덱스와 관련된 인덱스와 메소드가없는 이유입니다.

  2. LinkedList<T>노드 포인터 기반 컬렉션입니다. .NET에서는 이중 링크 구현입니다. 이는 이전 / 다음 요소가 현재 요소에 연결되어 있음을 의미합니다. 또한 데이터가 조각화되어 다른 RAM의 다른 위치에 다른 목록 개체를 배치 할 수 있습니다. 또한 LinkedList<T>for List<T>또는 Array 보다 더 많은 메모리가 사용됩니다 .

  3. List<T>.Net에서 Java의 대안입니다 ArrayList<T>. 이것은 이것이 배열 래퍼임을 의미합니다. 따라서 하나의 연속 된 데이터 블록으로 메모리에 할당됩니다. 할당 된 데이터 크기가 85000 바이트를 초과하면 Large Object Heap으로 이동합니다. 크기에 따라 힙 조각화 (가벼운 형태의 메모리 누수)가 발생할 수 있습니다. 그러나 크기가 85000 바이트 미만인 경우 메모리에서 매우 작고 빠른 액세스 표현을 제공합니다.

  4. 랜덤 액세스 성능과 메모리 소비에는 단일 연속 블록이 선호되지만 정기적으로 크기를 변경해야하는 컬렉션의 경우 일반적으로 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