배열 / 배열 목록에서 링크 된 목록을 사용하는시기


176

나는 많은 목록과 배열을 사용하지만 배열 목록을 연결된 목록보다 쉽게 ​​사용할 수는없는 시나리오를 아직 보지 못했습니다. 나는 누군가가 링크 된 목록이 눈에 띄게 더 나은 예를 줄 수 있기를 바랐습니다.


Java에서 ArrayList 및 LinkedList는 생성자 이외의 동일한 코드를 사용합니다. "연결된 목록보다 쉽게 ​​또는 쉽게 사용 된 배열 목록"은 의미가 없습니다. LinkedList보다 "쉬운"ArrayList의 예를 제공하십시오.
S.Lott December

2
이것도 확인하십시오. stackoverflow.com/questions/322715/…
NoNaMe


3
S.Lott 사실이 아닙니다. Java ArrayList는 Array를 감싸는 래퍼이며 일부 유틸리티 기능이 추가되었습니다. 연결된 목록은 분명히 연결된 목록입니다. developer.classpath.org/doc/java/util/ArrayList-source.html
kingfrito_5005

답변:


261

다음과 같은 경우 연결된 목록이 배열보다 선호됩니다.

  1. 목록에서 일정한 시간에 삽입 / 삭제해야합니다 (예 : 시간 예측 성이 절대적으로 중요한 실시간 컴퓨팅에서)

  2. 목록에 몇 개의 항목이 있는지 알 수 없습니다. 배열을 사용하면 배열이 너무 커지면 메모리를 다시 선언하고 복사해야 할 수 있습니다

  3. 당신은 어떤 요소에 무작위로 액세스 할 필요가 없습니다

  4. 목록 중간에 항목을 삽입 할 수 있기를 원합니다 (예 : 우선 순위 대기열)

다음과 같은 경우 배열이 바람직합니다.

  1. 요소에 인덱스 / 랜덤 액세스가 필요합니다

  2. 어레이에 올바른 양의 메모리를 할당 할 수 있도록 어레이의 요소 수를 미리 알고 있습니다.

  3. 모든 요소를 ​​순서대로 반복 할 때 속도가 필요합니다. 배열에서 포인터 수학을 사용하여 각 요소에 액세스 할 수 있지만 링크 된 목록의 각 요소에 대한 포인터를 기반으로 노드를 찾아야하므로 페이지 오류가 발생하여 성능이 저하 될 수 있습니다.

  4. 기억은 관심사입니다. 채워진 배열은 연결된 목록보다 적은 메모리를 사용합니다. 배열의 각 요소는 단지 데이터입니다. 각 링크 된 목록 노드에는 데이터와 링크 된 목록의 다른 요소에 대한 하나 이상의 포인터가 필요합니다.

.Net의 배열 목록과 같은 배열 목록은 배열의 이점을 제공하지만 동적으로 자원을 할당하여 목록 크기에 대해 너무 걱정할 필요가 없으며 아무 노력이나 노력없이 인덱스에서 항목을 삭제할 수 있습니다 셔플 링 요소. 성능 측면에서 배열 목록은 원시 배열보다 느립니다.


7
좋은 시작이지만 중요한 것은 생략합니다. 목록은 구조 공유를 지원하고 배열은 밀도가 높고 지역성이 더 좋습니다.
다리우스 베이컨

1
실제로 배열 목록과 배열의 성능 차이는 무시할 수 있습니다. 이것은 당신이 비슷한 것을 비교한다고 가정하고, 예를 들어 미리 크기를 알면 arraylist에 대해 알려줍니다.
svick

40
언제 LinkedList에 O (1) 삽입 / 삭제가 있습니까 ( 상시 삽입 / 삭제 를 말할 때의 의미는 무엇 입니까)? LinkedList의 중간에 물건을 삽입하면 O (n)이 항상
Pacerier

28
LinkedLists는 이미 반복 위치를 통해 삽입 위치에있는 경우 O (1) 삽입을 갖습니다. 항상 그런 것은 아닙니다.
Adam

4
우선 순위 대기열에 링크 된 목록을 사용하는 것은 매우 어리석은 생각입니다. 동적 배열 지원 힙은 O (lg n) 상각 삽입 및 최악의 대수 삭제 삭제를 허용하며 가장 빠른 실제 우선 순위 큐 구조 중 하나입니다.
Fred Foo

54

배열에는 O (1) 임의 액세스 권한이 있지만 항목을 추가하거나 제거하는 데 실제로 비용이 많이 듭니다.

연결된 목록은 항목을 추가하거나 제거하고 반복하는 데 실제로 저렴하지만 임의 액세스는 O (n)입니다.


3
연결된 목록의 양쪽 끝 에서 항목을 삽입 / 제거 할 때와 같이 배열 끝에서 항목을 제거하는 시간 은 일정합니다. 중간에 ... 너무별로.
Joey

1
@Joey는 Linked List O (n) 끝에 삽입 / 삭제되지 않습니까? 이미 두 번째 링크에 위치하지 않는 한 마지막 요소를 찾으려면 O (n) 단계가 필요합니다.
Alex Moore-Niemi

@ AlexMoore-Niemi : 단일 연결 목록의 경우 예. 그러나 많은 사람들이 앞뒤로 링크를 가지고 있으므로 끝을 가리키는 포인터를 유지합니다.
Joey

2
LL이 값을 정렬하지 않았지만 최악의 시나리오가 O (n) 인 경우를 제외하고 이중 연결 목록을 사용하면 앞뒤로 검색 할 수 있습니다.
securecurve

"링크 된 목록은 어디에서나 항목을 추가 또는 제거하고 반복하기에 실제로 저렴합니다"는 전적으로 사실이 아닙니다. 연결된 목록의 중간에있는 항목을 제거하려면 목록에서 해당 항목에 도달 할 때까지 처음부터 반복해야합니다. n = 목록의 항목 수인 O (n / 2) 시간입니다. 당신의 대답에서 그것은 배열에있는 것처럼 일정한 시간 O (1)을 제안하는 것처럼 들립니다. 연결된 목록의 헤드 / 루트 노드에서 추가 / 제거하는 일정 시간입니다.
Yawar Murtaza

22
Algorithm           ArrayList   LinkedList
seek front            O(1)         O(1)
seek back             O(1)         O(1)
seek to index         O(1)         O(N)
insert at front       O(N)         O(1)
insert at back        O(1)         O(1)
insert after an item  O(N)         O(1)

ArrayLists는 한 번만 읽을 수있는 많은 또는 어 펜더에는 좋지만 추가 또는 제거는 앞면 또는 가운데에는 좋지 않습니다.


14

다른 답변에 추가하기 위해 대부분의 배열 목록 구현은 목록 끝에 추가 용량을 예약하여 O (1) 시간 내에 목록 끝에 새 요소를 추가 할 수 있습니다. 배열 목록의 용량이 초과되면 더 큰 새 배열이 내부적으로 할당되고 모든 이전 요소가 복사됩니다. 일반적으로 새 배열은 기존 배열의 두 배 크기입니다. 이것은 평균적으로 으로 이러한 구현에서 배열 목록의 끝에 새로운 요소를 추가하는 것이 O (1) 연산 . 따라서 사전에 요소 수를 모르더라도 마지막에 요소를 추가하는 한 배열 목록은 요소를 추가하기 위해 연결된 목록보다 여전히 빠를 수 있습니다. 분명히 배열 목록의 임의의 위치에 새 요소를 삽입하는 것은 여전히 ​​O (n) 작업입니다.

액세스가 순차적 인 경우에도 배열 목록의 요소에 액세스하는 것이 연결된 목록보다 빠릅니다. 배열 요소가 연속 메모리에 저장되어 쉽게 캐시 될 수 있기 때문입니다. 연결된 목록 노드는 여러 다른 페이지에 분산 될 수 있습니다.

임의의 위치에 항목을 삽입하거나 삭제할 것임을 알고있는 경우에는 링크 된 목록 만 사용하는 것이 좋습니다. 배열 목록은 다른 모든 것보다 빠릅니다.


1
또한 동적 배열을 사용하여 링크 된 목록 (Abstract Data Type 의미)을 구현할 수도 있습니다. 이러한 방식으로 목록의 헤드에서 상수 시간 삽입 및 삭제를 상각하면서도 컴퓨터 캐시를 활용할 수 있으며 삽입 후 요소의 인덱스가있을 때 목록 중간에서 상수 시간 삽입 및 삭제를 할 수 있습니다. 완료 또는 삭제 될 요소의 색인 (shift / unshifts 필요 없음). 이에 대한 좋은 참조는 CLRS 10.3 입니다.
Domenico De Felice

7

중간에 항목을 삽입해야하고 배열의 크기를 조정하고 주변을 이동하지 않으려는 경우 목록의 장점이 나타납니다.

일반적으로 그렇지 않다는 것이 맞습니다. 나는 그런 몇 가지 매우 구체적인 사례를 보았지만 너무 많지는 않았습니다.


배열 이동 및 크기 조정은 중간에 반전을 수행 할 때 실제로 발생합니다. 할부 상환에 도달하지 않은 경우 크기를 조정하지 않고 이동 만하면됩니다.
securecurve

3

그것은 모두 반복하는 동안 어떤 유형의 작업을 수행 하느냐에 달려 있으며, 모든 데이터 구조는 시간과 메모리 사이에서 균형을 유지하며 필요에 따라 올바른 DS를 선택해야합니다. 따라서 LinkedList가 배열보다 빠르거나 그 반대 인 경우도 있습니다. 데이터 구조에 대한 세 가지 기본 조작을 고려하십시오.

  • 수색

배열은 인덱스 기반 데이터 구조이므로 array.get (index)는 O (1) 시간이 걸리며 linkedlist는 인덱스 DS가 아니므로 index <= n, n은 링크 된 목록의 크기입니다. 따라서 요소에 임의로 액세스 할 때 배열이 링크 된 목록보다 빠릅니다.

Q.이 뒤에 아름다움은 무엇입니까?

배열은 연속적인 메모리 블록이므로, 처음 액세스 할 때 캐시에 큰 청크가로드 될 것이므로 배열의 나머지 요소에 액세스하는 것이 상대적으로 빠릅니다. 캐시 누락은 캐시에있는 작업을 나타내므로 메모리에 비해 훨씬 빠르게 실행됩니다. 기본적으로 배열에서 순차적 요소 액세스가 캐시에있을 가능성을 최대화합니다. 링크 된 목록이 반드시 연속적인 메모리 블록에있는 것은 아니지만 목록에 순차적으로 나타나는 항목이 실제로 메모리의 서로 가까이에 정렬되어 있다는 보장은 없습니다.

  • 삽입

배열과 비교하여 LinkedList (Java에서) 삽입이 O (1) 연산이므로 LinkedList에서 쉽고 빠릅니다. 배열이 가득 찬 경우를 고려하십시오. 배열이 가득 차면 배열을 가득 채우면 내용을 새 배열에 복사해야합니다. 최악의 경우 O (n)의 ArrayList에 요소를 배치하는 반면, ArrayList는 배열의 끝을 제외한 다른 위치에 무언가를 삽입하면 색인을 업데이트해야합니다. 연결 된 목록의 경우 크기를 조정할 필요가 없으므로 단지 포인터를 업데이트하십시오.

  • 삭제

삽입과 같이 작동하며 배열보다 LinkedList에서 더 좋습니다.


2

이것들은 Collection에서 가장 일반적으로 사용되는 구현입니다.

배열 목록 :

  • 일반적으로 끝에 삽입 / 삭제 O (1) 최악의 경우 O (n)

  • 중간에 삽입 / 삭제 O (n)

  • 모든 위치를 검색 O (1)

연결 목록 :

  • 임의의 위치에 삽입 / 삭제 O (1) (요소에 대한 참조가있는 경우 참고)

  • 중간 O (n)에서 검색

  • 첫 번째 또는 마지막 요소 검색 O (1)

벡터 : 사용하지 마십시오. ArrayList와 유사하지만 모든 메소드가 동기화 된 이전 구현입니다. 멀티 스레딩 환경에서 공유 목록에 대한 올바른 접근 방식이 아닙니다.

해시 맵

O (1)의 키로 삽입 / 삭제 / 검색

TreeSet 삽입 / 삭제 / O (log N)에 포함

O (1)의 해시 셋 삽입 / 제거 / 포함 / 크기


1

실제로 메모리 지역은 실제 처리에 큰 성능 영향을 미칩니다.

"빅 데이터"프로세싱과 랜덤 액세스에서 디스크 스트리밍의 사용이 증가함에 따라 애플리케이션을 구성하는 것이 어떻게 대규모 성능을 크게 향상시킬 수 있는지 보여줍니다.

배열에 순차적으로 액세스 할 수있는 방법이 있다면 성능이 가장 뛰어납니다. 성능이 중요한 경우이를 목표로 설계하는 것이 적어도 고려되어야합니다.


0

흠, Arraylist는 다음과 같은 경우에 사용할 수 있습니다.

  1. 얼마나 많은 요소가 존재할지 확실하지 않습니다
  2. 인덱싱을 통해 모든 요소에 무작위로 액세스해야합니다.

예를 들어, 대화 상대 목록의 모든 요소 (크기를 알 수 없음)를 가져 와서 액세스해야합니다.


0

배열의 기수 정렬과 다항식 연산에는 링크 된 목록을 사용하십시오.


0

1) 위에서 설명한 것처럼 삽입 및 제거 작업은 ArrayList (O (n))에 비해 LinkedList에서 우수한 성능 (O (1))을 제공합니다. 따라서 응용 프로그램에 빈번한 추가 및 삭제가 필요한 경우 LinkedList가 최선의 선택입니다.

2) 검색 (get 메소드) 연산은 Arraylist (O (1))에서 빠르지 만 LinkedList (O (n))에서는 빠르지 않으므로 추가 및 제거 작업이 적고 더 많은 검색 작업 요구 사항이있는 경우 ArrayList가 가장 좋습니다.


0

가장 큰 차이점은 목록 상단에서 물건을 자주 삽입하거나 제거 해야하는지 여부입니다.

배열을 사용하면 배열 요소의 모든 인덱스가 이동해야하기 때문에 복잡성이 o (n)보다 목록의 맨 위에서 무언가를 제거하면됩니다.

링크 된 목록을 사용하면 노드를 작성하고 헤드를 다시 지정하고 다음을 이전 헤드로 참조를 지정하기 만하면 o (1)입니다.

목록의 끝에 자주 삽입하거나 제거 할 때는 복잡성이 o (1)이되고 재 인덱싱이 필요하지 않기 때문에 배열이 바람직하지만 연결된 목록의 경우 헤드에서 가야하기 때문에 o (n)이됩니다. 마지막 노드로.

나는 당신이 아마 이진 검색을 사용하기 때문에 링크 된 목록과 배열 모두에서 검색하는 것은 o (log n) 일 것이라고 생각합니다.


0

벤치마킹을했는데 무작위 삽입을 위해 목록 클래스가 실제로 LinkedList보다 빠릅니다.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = 20000;
            Random rand = new Random(12345);

            Stopwatch watch = Stopwatch.StartNew();
            LinkedList<int> ll = new LinkedList<int>();
            ll.AddLast(0);
            for (int i = 1; i < count; i++)
            {
                ll.AddBefore(ll.Find(rand.Next(i)),i);

            }
            Console.WriteLine("LinkedList/Random Add: {0}ms", watch.ElapsedMilliseconds);

            watch = Stopwatch.StartNew();
            List<int> list = new List<int>();
            list.Add(0);
            for (int i = 1; i < count; i++)
            {
                list.Insert(list.IndexOf(rand.Next(i)), i);

            }
            Console.WriteLine("List/Random Add: {0}ms", watch.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

링크 된 목록의 경우 900ms, 목록 클래스의 경우 100ms가 걸립니다.

후속 정수 목록을 작성합니다. 각각의 새로운 정수는 이미 목록에있는 난수 뒤에 삽입됩니다. 아마도 List 클래스는 배열보다 더 나은 것을 사용할 수 있습니다.


목록 인터페이스가 아닌 클래스
borgmater

0

배열은 지금까지 가장 널리 사용되는 데이터 구조입니다. 그러나 연결된 목록은 배열이 서 투르거나 비싸지 않은 고유 한 방식으로 유용합니다.

링크 된 목록은 크기가 달라질 수있는 상황에서 스택 및 대기열을 구현하는 데 유용합니다. 링크 된 목록의 각 노드는 대부분의 노드를 방해하지 않으면 서 밀거나 터질 수 있습니다. 중간 어딘가에 노드 삽입 / 삭제도 마찬가지입니다. 그러나 배열에서는 모든 요소를 ​​이동해야하므로 실행 시간 측면에서 값 비싼 작업입니다.

이진 트리 및 이진 검색 트리, 해시 테이블 및 시도는 데이터 구조의 일부이며, 적어도 C에서는이를 구성하기위한 기본 구성 요소로 연결된 목록이 필요합니다.

그러나 인덱스로 임의의 요소를 호출 할 수있는 상황에서는 링크 된 목록을 피해야합니다.


0

질문에 대한 간단한 대답은 다음과 같은 점을 사용하여 제공 할 수 있습니다.

  1. 유사한 유형의 데이터 요소를 수집해야하는 경우 배열이 사용됩니다. 반면, 링크 된 목록은 노드로 알려진 혼합 유형 데이터 링크 된 요소의 모음입니다.

  2. 배열에서 O (1) 시간에 모든 요소를 ​​방문 할 수 있습니다. 반면, 링크 된리스트에서 O (n) 시간이 걸리는 헤드에서 필요한 노드까지 전체 링크 된리스트를 탐색해야합니다.

  3. 배열의 경우 특정 크기를 처음에 선언해야합니다. 그러나 링크 된 목록의 크기는 동적입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.