배열 대 연결 목록


200

왜 누군가가 배열을 통해 연결된 목록을 사용하고 싶습니까?

연결된리스트를 코딩하는 것은 의심 할 여지없이 배열을 사용하는 것보다 약간 더 많은 작업이며 추가 노력이 필요한 이유가 무엇인지 궁금 할 것입니다.

링크 된 목록에서 새 요소를 삽입하는 것이 쉽지는 않지만 배열의 주요 작업입니다. 연결된 목록을 사용하여 데이터 세트를 저장하는 것과 비교하여 배열에 저장하는 것의 다른 장점이 있습니까?

이 질문의 중복없는 이 질문 이 질문에 일반 데이터 구조와 관련되는 동안 다른 문제는 특정 Java 클래스에 대해 구체적으로 요구하고 있기 때문이다.


1
관련 - <> ArrayList를 통해 LinkedList의를 <> 사용하는 경우? -Java이지만 배열 (ArrayList) 및 링크 된 목록은 아마도 모든 언어에서 동일한 성능을 가지고 있습니다.
Bernhard Barker


1
@rootTraveller 사실 내 질문이 먼저 게시되었으므로 해당 질문은이 질문과 중복됩니다.
Onorio Catenacci

답변:


147
  • 서로 다른 크기의 데이터를 연결된 목록에 저장하는 것이 더 쉽습니다. 배열은 모든 요소가 정확히 같은 크기라고 가정합니다.
  • 앞에서 언급했듯이 연결된 목록이 유기적으로 성장하기가 더 쉽습니다. 어레이의 크기를 미리 알고 있거나 확장이 필요할 때 다시 만들어야합니다.
  • 연결된 목록을 섞는 것은 무엇을 가리키는 지 변경하는 문제입니다. 배열 섞기가 ​​더 복잡하거나 메모리가 더 많이 걸립니다.
  • 반복이 "foreach"컨텍스트에서 발생하는 한 반복 성능을 잃지 않습니다.

19
크기가 다른 품목은 어떻게 다르게 취급됩니까? 연결된 목록은 다음 필드와 함께 고정 구조체를 사용하거나 (고정 크기 필요) 차량의 데이터에 대한 포인터를 저장합니다 (가변 크기 OK). 두 가지 방법 모두 벡터를 사용하여 쉽게 수행 할 수 있습니다. 셔플 링에도 동일합니다.
Brian

32
배열을 섞는 것이 복잡 하다고 말하고 싶습니다 .
휴 알렌

23
이 답변은 부정확하고 오해의 소지가 있습니다. (선언 할 때 배열의 크기를 알아야 할 필요는 없음)
Robert Paulson

35
데이터 지역성으로 인해 연결된 목록을 반복하는 것이 더 느리지 않습니까?
Firas Assaad

6
@Rick, 벡터는 일반적으로 필요한 공간을 전체적으로 할당하므로 크기가 증가 할 때마다 새로운 공간을 할당 할 필요가 없습니다. 결과적으로 벡터는 일반적으로 메모리를 많이 사용하지 않으며 연결된 목록보다 많지 않습니다.
Winston Ewert

179

또 다른 좋은 이유는 링크 된 목록이 효율적인 멀티 스레드 구현에 적합하다는 것입니다. 그 이유는 변경 사항이 로컬 인 경향이 있기 때문에 데이터 구조의 현지화 된 부분에서 삽입 및 제거를위한 포인터에만 영향을 미치기 때문입니다. 따라서 동일한 링크 목록에서 많은 스레드가 작동하도록 할 수 있습니다. 또한 CAS 유형 작업을 사용하여 잠금없는 버전을 만들고 무거운 잠금을 완전히 피할 수 있습니다.

연결된 목록을 사용하면 수정자가 발생하는 동안 반복자가 목록을 탐색 할 수도 있습니다. 수정 사항이 충돌하지 않는 낙관적 인 경우 반복자는 경합없이 계속할 수 있습니다.

배열을 사용하면 배열의 크기를 수정하는 모든 변경 사항이 배열의 많은 부분을 잠글 필요가 있으며 실제로 전체 배열에서 전역 잠금을 수행하지 않으면 수정 작업이 중단되지 않습니다.


9
알렉스-나에게 결코 일어나지 않았을 흥미로운 고려 사항입니다. 아주 좋은 대답입니다. 내가 할 수 있다면 당신을 두 번 찬성했습니다. :-)
Onorio Catenacci

5
이것으로 어디를 갈 수 있는지에 대한 좋은 아이디어는 건너 뛰기 목록 (특히 Java 6의 ConcurrentSkipListMap)을 살펴보십시오. CSLM은 뛰어난 성능을 가진 정렬 된 동시 맵입니다. 동기화 된 TreeMap보다 훨씬 낫습니다. tech.puredanger.com/2007/10/03/skip-lists
Alex Miller

...하는 것을 제외 ConcurrentSkipListMap또는 ConcurrentSkipListMap"목록"이름에 어딘가에 발생하더라도,리스트 수 없습니다. 둘 다 정렬되고 고유 한 키가 필요합니다. List, 즉 임의의 순서로 중복 요소를 허용하는 데이터 구조가 필요한 경우 적합하지 않으며 LinkedList동시에 업데이트 가능한 것과 같은 데이터 구조를 만들기 위해서는 많은 시간이 필요합니다 . 동시 대기열이나 대기열 만 필요한 경우 기존 예가 있지만 동시에 List... 이것이 가능하다는 확신이 들지 않습니다.
Holger

128

Wikipedia는 차이점에 대해 매우 좋은 섹션을 가지고 있습니다.

연결된 목록은 배열보다 몇 가지 장점이 있습니다. 요소는 무한대로 링크 된 목록에 삽입 될 수 있지만, 배열은 결국 채워지거나 크기를 조정해야합니다. 마찬가지로 많은 요소가 제거 된 어레이는 낭비로 비워 지거나 더 작아 져야합니다.

반면, 배열은 무작위 액세스를 허용하는 반면, 링크 된 목록은 요소에 대한 순차적 액세스 만 허용합니다. 실제로 연결된 단일 목록은 한 방향으로 만 순회 할 수 있습니다. 이로 인해 링크 목록은 힙 정렬과 같은 색인으로 요소를 빠르게 찾는 것이 유용한 응용 프로그램에 적합하지 않습니다. 참조 및 데이터 캐시의 지역성으로 인해 많은 시스템의 링크 된 목록보다 어레이에 대한 순차적 액세스가 빠릅니다. 연결된 목록은 캐시의 이점을 거의받지 않습니다.

연결된 목록의 또 다른 단점은 참조에 필요한 추가 저장소이며, 종종 문자 나 부울 값과 같은 작은 데이터 항목의 목록에는 실용적이지 않습니다. 또한 새로운 할당 요소마다 메모리를 별도로 할당하는 데 시간이 오래 걸리고 순진한 할당자가 낭비 될 수 있으며 일반적으로 메모리 풀을 사용하여 해결되는 문제입니다.

http://en.wikipedia.org/wiki/Linked_list


4
이것이 완벽한 해답입니다. 두 가지 장점과 단점을 간결하게 설명합니다.
Rick

고마워요)) 간단하지만 죽은 위키에서 보지 못했습니다)
Timur Fayzrakhmanov

58

나는 다른 것을 추가 할 것이다-목록은 순수한 기능을 할 수있다 데이터 구조 있다.

예를 들어, 동일한 끝 섹션을 공유하는 완전히 다른 목록을 가질 수 있습니다

a = (1 2 3 4, ....)
b = (4 3 2 1 1 2 3 4 ...)
c = (3 4 ...)

즉 :

b = 4 -> 3 -> 2 -> 1 -> a
c = a.next.next  

데이터를 복사하지 않고 가리키는 되 abc .

그들이 불변 변수를 사용하여 함수형 언어에서 인기있는 이유입니다 - prependtail작업은 원래의 데이터를 복사 할 필요없이 자유롭게 발생할 수 있습니다 - 당신은 불변 같은 데이터를 처리 할 때 매우 중요한 기능입니다.


4
그러나 내가 생각해 본 적이없는 또 다른 매우 흥미로운 고려 사항. 감사합니다.
Onorio Catenacci

파이썬에서 어떻게 할 수 있습니까?
overexchange

29

리스트의 중간에 삽입하는 것이 더 쉬울뿐 아니라 배열보다 링크 된리스트의 중간에서 삭제하는 것이 훨씬 쉽습니다.

그러나 솔직히, 나는 연결 목록을 사용한 적이 없다. 빠른 삽입 및 삭제가 필요할 때마다 빠른 조회도 필요했기 때문에 HashSet 또는 Dictionary로 이동했습니다.


2
삽입과 삭제는 대부분의 시간을 검색 한 후에 발생하므로 시간 복잡성의 합도 고려해야합니다.
MA Hossain Tonu

28

두 개의 연결된 목록 (특히 두 개의 이중 연결된 목록)을 병합하는 것이 두 배열을 병합하는 것보다 훨씬 빠릅니다 (병합이 파괴적이라고 가정). 전자는 O (1)을, 후자는 O (n)을 사용합니다.

편집 : 명확히하기 위해 병합 정렬이 아닌 정렬되지 않은 의미에서 "병합"을 의미했습니다. 아마도 "연결하는"것이 더 나은 단어 일 것입니다.


2
한 목록을 다른 목록에 추가하는 경우에만 가능합니다. 실제로 두 개의 정렬 된 목록을 병합하는 경우 O (1)보다 큰 로그가 필요합니다.
Herms

3
@Herms, 추가 메모리를 할당하지 않고 두 목록을 순회하고 포인터를 적절히 설정하면 정렬 된 두 개의 연결 목록을 병합 할 수 있습니다. 두 개의 배열을 병합하면 일반적으로 하나 이상의 추가 배열이 필요합니다.
Paul Tomblin

1
예, 목록을 병합하는 것이 메모리 효율이 높지만 실제로 내가 언급 한 것은 아닙니다. 연결된 목록을 병합하는 것이 O (1)라고 말하는 것은 사건을 명확히하지 않으면 서 매우 오도됩니다.
Herms

@Herms 병합 목록은 합리적인 데이터 모델에서 배열을 병합하는 것보다 메모리 효율성이 떨어집니다.
Alexei Averchenko

2
Alexei Averchenko : O (1) 메모리를 사용하여 두 목록을 연결하거나 정렬 된 두 목록을 병합 정렬 할 수도 있습니다. 배열이 메모리에 이미 인접하지 않은 경우 두 배열을 연결하려면 반드시 O (n) 메모리가 필요합니다. 당신이 목표로하는 요점은 n 개의 요소 목록과 n 개의 요소 배열이 모두 O (n) 메모리를 사용하지만 계수가 연결된 목록의 경우 더 높다는 것입니다.
rampion

17

ArrayList 및 LinkedList에 대해 널리 인정되지 않는 인수는 디버깅하는 동안 LinkedLists가 불편 하다는 것입니다 입니다. 유지 보수 개발자가 프로그램을 이해하는 데 소요되는 시간 (예 : 버그 찾기, 증가) 및 IMHO는 때때로 엔터프라이즈 응용 프로그램에서 메모리 향상의 성능 향상 또는 바이트 수의 나노초를 정당화하지 않습니다. 때로는 (물론 응용 프로그램 유형에 따라 다름) 몇 바이트를 낭비하는 것이 좋지만 유지 관리가 용이하거나 이해하기 쉬운 응용 프로그램이 있습니다.

예를 들어, Java 환경에서 Eclipse 디버거를 사용하면 ArrayList를 디버깅하면 매우 이해하기 쉬운 구조가 나타납니다.

arrayList   ArrayList<String>
  elementData   Object[]
    [0] Object  "Foo"
    [1] Object  "Foo"
    [2] Object  "Foo"
    [3] Object  "Foo"
    [4] Object  "Foo"
    ...

반면에, LinkedList의 내용을보고 특정 객체를 찾는 것은 LinkedList 내부를 걸러내는 데 필요한인지 오버 헤드는 말할 것도없고 Expand-The-Tree 클릭 악몽이됩니다.

linkedList  LinkedList<String>
    header  LinkedList$Entry<E>
        element E
        next    LinkedList$Entry<E>
            element E   "Foo"
            next    LinkedList$Entry<E>
                element E   "Foo"
                next    LinkedList$Entry<E>
                    element E   "Foo"
                    next    LinkedList$Entry<E>
                    previous    LinkedList$Entry<E>
                    ...
                previous    LinkedList$Entry<E>
            previous    LinkedList$Entry<E>
        previous    LinkedList$Entry<E>

17

우선, C ++ 링크 목록에서 배열보다 작업하기가 훨씬 더 쉬워서는 안됩니다. 연결된 목록에 std :: list 또는 부스트 포인터 목록 을 사용할 수 있습니다 . 연결된 목록과 배열의 주요 문제는 포인터와 끔찍한 임의 액세스에 필요한 추가 공간입니다. 당신이 연결 목록을 사용해야합니다

  • 데이터에 무작위로 액세스 할 필요가 없습니다
  • 특히 목록 중간에 요소를 추가 / 삭제합니다.

14

저에게는 이렇습니다

  1. 접속하다

    • 연결된 목록 은 요소에 대한 순차적 액세스 만 허용합니다. 따라서 알고리즘 복잡도는 O (n)의 차수입니다
    • 배열 은 해당 요소에 무작위로 액세스 할 수 있으므로 복잡도는 O (1)
  2. 저장

    • 연결된 목록 에는 참조를위한 추가 저장소가 필요합니다. 따라서 문자 또는 부울 값과 같은 작은 데이터 항목 목록에는 실용적이지 않습니다.
    • 어레이 는 다음 데이터 항목을 가리 키기 위해 추가 스토리지가 필요하지 않습니다. 각 요소는 인덱스를 통해 액세스 할 수 있습니다.
  3. 크기

    • 링크 된 목록 의 크기 본질적으로 동적입니다.
    • 배열 의 크기는 선언으로 제한됩니다.
  4. 삽입 / 삭제

    • 링크 된 목록 에서 요소를 무기한 삽입하고 삭제할 수 있습니다 .
    • 배열 의 값 삽입 / 삭제 는 매우 비쌉니다. 메모리 재 할당이 필요합니다.

2 번 2 번과 2 번 3 번 :)
Hengameh

빈 배열을 선언 한 다음 필요에 따라 데이터를 계속 추가 할 수 있습니다. 여전히 고정 크기는 어떻게합니까?
HebleV

11

두가지:

연결된 목록을 코딩하는 것은 의심 할 여지없이 배열을 사용하는 것보다 약간 더 많은 작업이며 추가 노력이 필요한 이유가 무엇인지 궁금했습니다.

C ++를 사용할 때 연결된 목록을 코딩하지 마십시오. STL을 사용하십시오. 구현이 얼마나 어려운지는 대부분 이미 구현되어 있기 때문에 한 데이터 구조를 다른 데이터 구조보다 선택해야하는 이유가되어서는 안됩니다.

배열과 연결된 목록의 실제 차이점에 대해서는 구조체 사용 계획을 세우는 것이 가장 중요합니다. C ++에서 크기 조정 가능한 배열의 용어이므로 vector라는 용어를 사용합니다.

주어진 인덱스에 도달하기 위해리스트를 순회해야하므로 벡터가 메모리에 인접 해 있고 포인터 수학을 사용하여 링크리스트에 인덱싱하는 것이 느립니다.

하나의 링크 만 업데이트하면되기 때문에 링크 된 목록의 끝이나 시작 부분에 쉽게 추가 할 수 있습니다. 벡터에서는 내용의 크기를 조정하고 복사해야 할 수도 있습니다.

한 쌍의 링크를 끊고 다시 연결하기 만하면 목록에서 항목을 쉽게 제거 할 수 있습니다. 주문에서 신경 쓰는지에 따라 벡터에서 항목을 제거하는 것이 더 빠르거나 느려질 수 있습니다. 제거하려는 항목의 맨 위에있는 마지막 항목을 바꾸는 것이 더 빠르며, 아래로 이동 한 후에는 모든 항목이 느리지 만 순서는 유지됩니다.


위의 누군가에게 말했듯이, 나는 그 질문을 나에게 주어진 방식과 관련 시키려고했습니다. 어쨌든 C ++에서 배열 (또는 내 자신의 링크 목록)을 사용하지 않을 것입니다. 두 가지 모두의 STL 버전을 사용합니다.
Onorio Catenacci

10

Eric Lippert는 최근에 배열을 보수적으로 사용해야하는 이유 중 하나에 대해 을 올렸습니다 .


2
분명히 좋은 게시물이지만 링크 된 목록과 배열의 토론에서는 관련이 없습니다.
Robert Paulson

2
Eric의 기사 중 많은 부분이 목록 구현을 지키지 않고 배열의 단점과 목록의 장점을 모두 설명하기 때문에 관련이 있다고 제안합니다.
Bevan

8

빠른 삽입 및 제거는 실제로 링크 된 목록에 가장 적합한 인수입니다. 구조가 동적으로 커지고 동적 스택 및 대기열과 같은 요소에 대한 일정한 시간 액세스가 필요하지 않으면 연결된 목록을 선택하는 것이 좋습니다.


7

빠른 방법은 다음과 같습니다. 항목을 더 빨리 제거 할 수 있습니다.


7

연결 목록은 컬렉션이 지속적으로 증가 및 축소 될 때 특히 유용합니다. 예를 들어, 배열을 사용하여 대기열을 구현하려고 시도하는 것은 상상하기 어렵습니다. 다른 한편으로, 그것은 연결 목록으로 사소한 것입니다.


4
여전히 빠르고 효율적인 작업을 많이하지 않고도 어레이 기반 대기열을 가질 수 있습니다. 어떤 인덱스가 "헤드"이고 어떤 인덱스가 "테일"인지 추적해야합니다. 고정 크기 대기열 (예 : 커널의 키보드 버퍼)이 필요한 경우 상당히 잘 작동합니다.
Herms

3
선호하는 알고리즘 참조에서 찾아 보려면 "원형 버퍼"라고합니다.
Steve Jessop

7

목록의 중간에 추가 및 제거하는 것 외에도 링크 된 목록은 동적으로 커지거나 줄어들 수 있기 때문에 더 좋아합니다.


6
벡터 (= 기본적으로 배열)도 그렇게 할 수 있으며 그에 대한 상각 비용은 일반적으로 지역의 참조 문제로 인해 목록의 비용보다 적습니다.
Konrad Rudolph

7

더 이상 아무도 자신의 연결 목록을 코딩하지 않습니다. 어리석은 일이야 연결된 목록을 사용하는 데 더 많은 코드가 필요하다는 전제는 잘못입니다.

요즘에는 링크 된 목록을 작성하는 것이 학생들을위한 연습이므로 개념을 이해할 수 있습니다. 대신 모두가 미리 작성된 목록을 사용합니다. C ++에서는 질문에 대한 설명을 기반으로 stl 벡터 ( #include <vector>)를 의미합니다 .

따라서 배열 목록과 배열을 선택하는 것은 전적으로 앱의 요구와 관련하여 각 구조의 다른 특성을 측정하는 것입니다. 추가 프로그래밍 부담을 극복하면 결정에 영향을 미치지 않아야합니다.


2
Er..umm .. std :: vector는 연결된 목록이 아닌 배열입니다. 표준 링크리스트는 std :: list입니다.
James Curran

1
예, 그러나 벡터는 op가 동적 배열 교체를 요구하는 것에 더 가깝다고 생각합니다.
Joel Coehoorn

@Joel, 나는 C ++을 배우려고하는이 동료가 나에게 제기 한 질문을 관련 시키려고했습니다. 나는 내 자신의 링크 된 목록을 코딩하는 것을 귀찮게하지 않을 것이지만 그것이 그가 나에게 요청한 방법입니다. :-)
Onorio Catenacci

사용자 정의 컴파일러가있는 메모리 제한 환경 (마이크로 컨트롤러)에서는 모든 언어 (예 : C ++의 컨테이너)가 구현되지 않습니다. 따라서 자체 링크 목록을 코딩해야 할 수도 있습니다. nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
민 트란

6

실제로 효율성의 문제입니다. 연결된 목록 내에서 요소를 삽입, 제거 또는 이동하는 오버 헤드 (간단히 스왑하지 않는 경우)가 최소화됩니다. 즉, 작업 자체는 O (1), 배열의 O (n)입니다. 이는 데이터 목록에서 많은 작업을 수행하는 경우 큰 차이를 만들 수 있습니다. 운영 방식에 따라 데이터 유형을 선택하고 사용중인 알고리즘에 가장 효율적인 데이터 유형을 선택했습니다.


6

배열은 정확한 수의 항목을 알 수있는 위치와 색인으로 검색하는 것이 적합한 위치에 적합합니다. 예를 들어, 압축없이 주어진 순간에 비디오 출력의 정확한 상태를 저장하려면 [1024] [768] 크기의 배열을 사용합니다. 이것은 내가 필요한 것을 정확하게 제공 할 것이고, 주어진 픽셀의 값을 얻는 데 목록이 훨씬 느려질 것입니다. 배열이 의미가없는 곳에서는 일반적으로 데이터를 효과적으로 처리하기위한 목록보다 더 나은 데이터 유형이 있습니다.


6

배열 대 연결 목록 :

  1. 조각난 메모리로 인해 때때로 배열 메모리 할당이 실패합니다.
  2. 모든 요소에 연속 메모리 공간이 할당되므로 배열에서 캐싱이 더 좋습니다.
  3. 코딩은 배열보다 복잡합니다.
  4. 배열과 달리 링크 된 목록에는 크기 제한이 없습니다.
  5. 연결 목록에서는 삽입 / 삭제가 더 빠르며 어레이에서는 액세스가 더 빠릅니다.
  6. 멀티 스레딩 관점에서 연결 목록이 더 좋습니다.

-1 : 열거 된 것이 아니라 이들 모두를 입증해야합니다.
John Saunders

각 포인트는 이미 위의 답변에서 설명되었습니다. 후발 자이기 때문에 열거하는 것 외에 다른 옵션이 없었습니다. BTW, 어느 쪽을 설명 하시겠습니까?
AKS

그들이 이미 설명 되었다면, 왜 대답하고 있습니까?
John Saunders

2
토론에 대한 요약 된 견해를 제공 할 것입니다. 그리고 나는 그런 유형의 답변을 좋아해서 반복해서 같은 설명을 읽을 필요가 없습니다. 저는 저와 같은 사고 방식을 가진 사람들을 위해 해냈습니다. 다른 ppl은 다른 스타일을 가지고 있습니다. 새로운 것은 없다.
AKS

3

배열은 본질적으로 정적이므로 메모리 할당과 같은 모든 작업은 컴파일 시점에만 발생합니다. 따라서 프로세서는 런타임에 적은 노력을 기울여야합니다.


3

요소를 추가하고 제거하여 수정하려는 순서 집합이 있다고 가정하십시오. 또한 나중에 이전 또는 다음 요소를 얻을 수있는 방식으로 요소에 대한 참조를 유지하는 기능이 필요합니다. 예를 들어, 책의 할 일 목록 또는 단락 세트입니다.

먼저 집합 자체 외부의 객체에 대한 참조를 유지하려면 객체 자체를 저장하지 않고 배열에 포인터를 저장하게 될 수 있습니다. 그렇지 않으면 배열에 삽입 할 수 없습니다. 개체가 배열에 포함 된 경우 삽입하는 동안 개체가 이동하고 이에 대한 포인터가 유효하지 않게됩니다. 배열 인덱스도 마찬가지입니다.

첫 번째 문제는 직접 언급했듯이 삽입-연결 목록은 O (1)에 삽입 할 수 있지만 배열에는 일반적으로 O (n)이 필요합니다. 이 문제는 부분적으로 극복 할 수 있습니다. 읽기와 쓰기가 최악의 경우 로그와 같은 배열과 같은 직통 액세스 인터페이스를 제공하는 데이터 구조를 만들 수 있습니다.

두 번째로 더 심각한 문제는 다음 요소를 찾는 요소가 O (n)이라는 것입니다. 집합이 수정되지 않은 경우 포인터 대신 요소의 색인을 참조로 유지할 수 있으므로 find-next를 O (1) 연산으로 만들 수 있지만 객체 자체에 대한 포인터 만 있으면됩니다. 전체 "배열"을 스캔하는 것 이외의 배열에서 현재 인덱스를 결정합니다. 이는 배열에서 극복 할 수없는 문제입니다. 삽입을 최적화 할 수 있어도 찾기-다음 유형 작업을 최적화하기 위해 할 수있는 일은 없습니다.


"읽기와 쓰기가 최악의 경우 로그와 같은 배열과 같은 기본적인 액세스 인터페이스를 제공하는 데이터 구조를 만들 수 있습니다."
헨 가메

1
Wikipedia의 Dynamic Array / Vriants 섹션에있는 것들이 있습니다. 비록 내가 생각했던 것은 아니지만 ... 페이지가 있지만 키가없는 구조와 같은 b + 트리를 상상해보십시오. 각 중간 페이지는 각 하위 페이지에 얼마나 많은 요소가 있는지 기억하지만 리프 페이지는 작은 배열의 요소. 리프 페이지에 요소를 삽입 할 때 공간을 만들기 위해 페이지를 반으로 이동 한 다음 모든 조상 페이지에서 항목 수를 업데이트하고 업데이트해야합니다. 요소 #N을 찾을 때 N을 교차 할 때까지 하위 페이지 항목 수를
더한

3

배열에서는 O (1) 시간에 모든 요소에 액세스 할 수있는 권한이 있습니다. 따라서 이진 검색 빠른 정렬 등과 ​​같은 작업에 적합합니다. 반면에 연결된 목록은 O (1) 시간과 같이 삽입 삭제에 적합합니다. 둘 다 장점과 단점이 있으며, 구현하려는 것보다 다른 것을 선호합니다.

더 큰 문제는 우리가 둘의 하이브리드를 가질 수 있다는 것입니다. 파이썬과 펄이 목록으로 구현하는 것과 같은 것.


3

연결리스트

삽입에 관해서는 더 바람직합니다! 기본적으로 포인터를 다루는 것입니다.

1-> 3-> 4

삽입 (2)

1 ........ 3 ...... 4
..... 2

드디어

1-> 2-> 3-> 4

3에서 2 포인트에서 하나의 화살표와 2에서 1 포인트의 화살표

단순한!

그러나 배열에서

| 1 | 3 | 4 |

삽입 (2) | 1 | 3 | | 4 | | 1 | | 3 | 4 | | 1 | 2 | 3 | 4 |

누구나 차이를 시각화 할 수 있습니다! 4 개의 인덱스에 대해서만 3 단계를 수행합니다.

배열 길이가 백만이면 어떻게 되나요? 배열이 효율적입니까? 내 대답은 아니오 야! :)

같은 일이 삭제됩니다! Linked List에서 간단히 포인터를 사용하여 객체 클래스에서 요소와 다음을 무효화 할 수 있습니다! 그러나 배열의 경우 shiftLeft ()를 수행해야합니다.

희망이 도움이됩니다! :)


3

Linked List는 어레이보다 유지 관리해야 할 오버 헤드가 많으며,이 모든 지점이 합의 된 경우 추가 메모리 저장소가 필요합니다. 그러나 배열이 할 수없는 몇 가지가 있습니다. 대부분의 경우 길이가 10 ^ 9 인 배열을 원한다고 가정하면 하나의 연속 메모리 위치를 가져와야하므로 얻을 수 없습니다. 연결된 목록은 구세주가 될 수 있습니다.

데이터가 포함 된 여러 항목을 저장하려는 경우 링크 된 목록에서 쉽게 확장 할 수 있습니다.

STL 컨테이너에는 일반적으로 씬 뒤에 링크 된 목록 구현이 있습니다.


3

1- 링크 된 목록은 동적 데이터 구조이므로 런타임시 메모리를 할당 및 할당 해제하여 확장 및 축소 할 수 있습니다. 따라서 링크 된 목록의 초기 크기를 제공 할 필요가 없습니다. 노드 삽입 및 삭제가 훨씬 쉽습니다.

링크 된 목록의 2 크기는 런타임에 증가 또는 감소 할 수 있으므로 메모리 낭비가 없습니다. 배열의 경우 10 크기의 배열을 선언하고 6 개의 요소 만 저장하면 4 개의 요소 공간이 낭비되는 것처럼 많은 메모리 낭비가 있습니다. 필요한 경우에만 메모리가 할당되므로 링크 된 목록에는 이러한 문제가 없습니다.

3- 스택 및 큐와 같은 데이터 구조는 링크 된 목록을 사용하여 쉽게 구현할 수 있습니다.


2

링크 된 목록을 사용해야하는 이유는 요소를 쉽게 삽입 할 수 있기 때문입니다 (제거도 가능).

포인터가 많은 공간을 차지한다는 단점이 있습니다.

그리고 그 코딩에 대해 더 어렵습니다. 일반적으로 코드 링크 목록이 필요하지 않거나 STL에 포함되어 있으며 여전히해야 할 경우 그렇게 복잡하지 않습니다.


2
포인터는 많은 공간을 차지합니까? 실제로는 아닙니다. 링크 된 부울 목록을 저장하는 경우 포인터가 많은 공간을 차지하는 것이 현명합니다. 그러나 복잡한 객체 (일반적으로 경우)를 저장하는 경우 포인터는 무시할 수 있습니다.
Herms

미소를 잊어 버렸다 :) 그러나 '는 할 수 없다'고 말했다.
user15453

1

또한 링크 목록이 배열보다 낫다고 생각합니다. 링크 목록에서는 순회하지만 배열에서는 순회하지 않기 때문에


1

언어에 따라 이러한 단점과 장점 중 일부를 고려할 수 있습니다.

C 프로그래밍 언어 : 일반적으로 구조체 포인터를 통해 연결된 목록을 사용하는 경우 메모리 누수가 발생하지 않도록 특별히 고려해야합니다. 앞에서 언급했듯이 링크 된 목록은 셔플하기 쉽습니다. 모든 작업이 포인터를 변경하는 것이기 때문에 모든 것을 해제하는 것을 기억해야합니까?

Java : Java에는 자동 가비지 수집 기능이 있으므로 메모리 누수는 문제가되지 않지만 고급 프로그래머에게는 숨겨진 목록이 링크 된 목록의 구현 세부 사항입니다. 목록 중간에서 노드를 제거하는 등의 방법은 일부 언어 사용자가 예상하는 것보다 절차가 더 복잡합니다.


1

왜 배열을 통해 연결된 목록입니까? 일부 사람들은 이미 언급했듯이 삽입 및 삭제 속도가 더 빠릅니다.

그러나 어쩌면 우리는 어느 한도의 한계에 부딪치지 않고 동시에 최고를 얻을 필요가 없습니다.

배열 삭제의 경우 '삭제 된'바이트를 사용하여 행이 삭제되었다는 사실을 나타내므로 배열을 다시 구성 할 필요가 없습니다. 삽입 또는 급변하는 데이터의 부담을 덜기 위해 링크 된 목록을 사용하십시오. 그런 다음이를 참조 할 때 먼저 논리를 검색 한 다음 다른 논리를 검색하십시오. 따라서, 이들을 조합하여 사용하면 둘 다 최고를 얻을 수 있습니다.

정말로 큰 배열을 가지고 있다면, 가장 작은 배열을 가장 작은 다른 배열 또는 링크 된 목록과 결합 할 수 있습니다. 필요한 것이 짧은 링크 목록 또는 배열에 없으면 큰 배열로 이동합니다. 거기에서 발견되면 '가장 최근에 사용한 것들이 재사용 될 가능성이 가장 높다'는 가정에서 더 작은 링크 된 목록 / 배열에 추가 할 수 있습니다. 이는 많은 경우에 해당되며 .ASP 보안 권한 검사 모듈에서 쉽고 우아하고 인상적인 속도로 해결해야하는 문제를 해결했습니다.


1

많은 사람들이 링크 된 목록 대 배열의 주요 발전 / 표시에 대해 언급했지만 대부분의 비교는 하나가 다른 것보다 낫거나 나쁩니다. 배열에서 임의 액세스를 할 수 있지만 링크 된 목록 및 기타에서는 불가능합니다. 그러나 이것은 링크 목록과 배열이 비슷한 응용 프로그램에 적용될 것이라고 가정합니다. 그러나 정답은 특정 응용 프로그램 배포에서 링크 목록이 배열보다 선호되고 그 반대도 마찬가지입니다. 사전 응용 프로그램을 구현한다고 가정하면 무엇을 사용 하시겠습니까? 배열 : mmm 그것은 바이너리 검색 및 기타 검색 알고리즘을 통해 쉽게 검색 할 수 있지만 링크 목록이 더 나은 방법을 생각할 수 있습니다. 사전에서 "Blob"을 검색하고 싶습니다. A-> B-> C-> D ---->의 링크 목록을 갖는 것이 합리적입니까?

A -> B -> C -> ...Z
|    |    |
|    |    [Cat, Cave]
|    [Banana, Blob]
[Adam, Apple]

위의 접근 방식이 더 좋거나 [Adam, Apple, Banana, Blob, Cat, Cave]의 평평한 배열입니까? 배열에서도 가능할까요? 따라서 링크 목록의 주요 장점은 다음 요소뿐만 아니라 다른 링크 목록 / 배열 / 힙 / 또는 기타 메모리 위치를 가리키는 요소를 가질 수 있다는 것입니다. 배열은 저장하려는 요소의 블록 크기로 슬라이스 된 하나의 평평한 연속 메모리입니다. 반면에 링크 목록은 비 연속 메모리 단위 (임의의 크기 일 수 있으며 무엇이든 저장할 수 있음)의 덩어리이며 각각을 가리키는 당신이 원하는 다른 방법. 마찬가지로 USB 드라이브를 만들고 있다고 말할 수 있습니다. 이제 파일을 배열 또는 링크 목록으로 저장 하시겠습니까? 나는 당신이 내가 가리키는 것을 생각한다고 생각합니다 :)

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