배열 대 연결 목록


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  

데이터를 복사하지 않고 가리키는 되 a로 b및c .

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


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.