3- 단일 연결리스트 데이터 구조

그 다음에 확장 정전기 배열 동적 배열 동적 배열을 만든 후, 여기에 다시 단방향 링크리스트를 통해 달성 동적 배열을 만든다. 먼저, 첫 번째는 목록의 중요성을 이해 할 수 있도록, 단점을 동적 배열을 분석합니다. 첫째, 추가 및 아래 전에 동적 배열을 삭제하는 과정을 검토 :

동적 배열 요소, 요소가 역방향 회전을 이동할 필요가 있으므로 최악의 경우는, 배열 요소의 헤드에 삽입 될 때 추가 된 현재 요소 피연산자들의 수에 따라, 복잡한 바람직 O (N), 인 상황이 배열 움직이는 요소의 말미에 추가되는 복잡도는 O (1)이다. 평균 복잡도가 O (N)이다. 작업의 확장을 추가 할 때마다 필요하지 않기 때문에 복잡도가 O (n)이 때 때 오버 플로우 확장, 용량 만 필요, 확장은 O (1) 상각 복잡성은 여전히 ​​O입니다하지 않을 때 (1) .

삭제하고 실질적으로 동일한를 추가, 꼬리 최상의 경우의 복잡성이 팀 O (1)을 삭제하는 것입니다, 최악의 경우가 처음 팀을 삭제하는 것입니다, 복잡도는 O (N), 평균 복잡도 (n)이 O입니다.

시간 인덱스 값 반면, 본질적으로 직접 배열 인덱스 값으로하기 때문에, 배열 값 복잡도 요소의 복잡성이 O 촬영되도록, O (1) (1).

주 : 배열의 값으로부터 이송 할 필요는 없지만, 직접 어드레스 값 계산 복잡도는 O를 통하여 (1).

그런 다음 목록은 그것의 정적 배열보다 더 빨리되지 않습니다,의는 다음, 사용자 정의 단일 연결리스트를 구현 알고 비교할 수 있습니다. 첫째, 미리 알림, 단방향 연결리스트 오, 너무 빨리 생각하지 않을 수 있습니다.

다른 배열에서 첫 번째 모양과 메모리 연결리스트

이 목록은 다른 포인팅하는 노드라고 각 유닛의 링크 된리스트에 저장되어, 저장되는 단방향 링크리스트, 각 노드에 저장하여 두 값의 저장 소자에 대한 포인터를 메모리의 연속 아니다 다음 노드에 대한 포인터를리스트가 긴리스트는 제 1 노드를 획득하기 위해, 노드 목록에 액세스 할 수있는 각 노드에서 노드에 대한 포인터를 지정하여 현재 노드에서 찾을 수 있으며, 그것은 동시에 할 수있다 목록의 모든 요소를 ​​얻을.

방법 연결리스트 노드 구조

이러한 모습 - 방법 연결 목록은 각 노드가 해당 객체가 두 멤버 변수를 가지고있다, 오브젝티브 C 언어가 아닌 매우 간단합니다, 저장된 값은이고 다른 하나는, 다음 노드 객체를 저장할 수있다 노드 객체의 단방향 연결리스트를 선언 :

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface JKRSingleLinkedListNode : NSObject

@property (nonatomic, strong, nullable) id object;
@property (nonatomic, strong, nullable) JKRSingleLinkedListNode *next;

- (instancetype)init __unavailable;
+ (instancetype)new __unavailable;
- (instancetype)initWithObject:(nullable id)object next:(nullable JKRSingleLinkedListNode *)next;

@end

NS_ASSUME_NONNULL_END
复制代码

방법 연결리스트 구조

헤드 노드 목록을 얻을 수있는 유일한 방법 때문에, 당신은 모든 노드에 액세스 할 수 있습니다, 다음 단방향 연결리스트는 멤버 변수 만이 필요 저장해야, 하나는이 목록의 저장 길이 _size입니다. 또 다른이 _first이며,리스트의 첫 번째 노드를 저장합니다.

주 : 인터페이스 선언 모든 상위 클래스의 정의를 참조 또한 상위 클래스는 상위 클래스에 저장 _size 정적 배열을 통해 동적 배열 확장 , 문서의 전체 소스 엔드.

#import "JKRBaseList.h"
#import "JKRSingleLinkedListNode.h"

NS_ASSUME_NONNULL_BEGIN

@interface JKRSingleLinkedList : JKRBaseList {
    // NSUInteger _size; 
    JKRSingleLinkedListNode *_first;
}

@end

NS_ASSUME_NONNULL_END
复制代码

여기서 이해를 더 직접적인 방법 링크드리스트 구조 일 수 단방향 연결 목록의 전체 메모리의 구조도이다 :

인덱스 노드를 찾기

특정한 하나는 지수 노드에 의해 얻어지는 경우, 상기리스트 구조도 볼 수있다. 머리 노드리스트 객체의 길이리스트 및리스트를 저장 노드는 인덱스 차를 발견 할 때까지 다시 하나씩 찾아야 다음 포인터가 처음부터 다시 시작해야 노드입니다.

헤드 노드에 전용 액세스, 하나 명의 방문은 노드 인덱스 0을 복용, 복잡성 지수 시간을 필요 따라. 마지막 액세스 노드가 헤드 노드는 엔드 노드에 대한 액세스 권한이 필요 방문의 수는 노드의 수에 따라 달라집니다. O (N)의 요약 평균 시간 복잡도합니다.

- (JKRSingleLinkedListNode *)nodeWithIndex:(NSInteger)index {
    [self rangeCheckForExceptAdd:index];
    JKRSingleLinkedListNode *node = _first;
    for (NSInteger i = 0; i < index; i++) {
        node = node.next;
    }
    return node;
}
复制代码

인덱스 값으로

위 달성 된 노드 단지 노드를 얻기 위해 메소드를 호출 인덱스 위치를 얻기 위해, 다음 노드에 저장된 값을 반환합니다. 시간 복잡도 노드 찾기 : O (N)를

- (id)objectAtIndex:(NSUInteger)index {
    return [self nodeWithIndex:index].object;
}
复制代码

노드 추가

노드는리스트의 중간에 삽입

그림과 같이 노드는 우리가 삽입되는 노드의 위치에 대한 목록 인덱스를 필요로이 경우 목록에있는 세 개의 노드가,가,리스트의 중간에 삽입됩니다

이 시점에서 원래의 인덱스 노드 (1) 옆에 포인트가 새 노드에 다음 포인트의 인덱스 노드 0을하는 것입니다, 새로운 노드를 할 필요가 :

이러한 삽입이 성공적으로 두 개의 노드에 연결리스트 노드에 삽입됩니다 :

링크 된 목록에 헤드 노드를 삽입

연결리스트의 헤드에 삽입 노드 아래 :

그런 다음 새 노드의 다음 _first 원래 목록과 새 노드에 _first 포인트의 목록을 가리 키도록해야합니다 :

후 성공적으로 목록 헤더 연결리스트의 노드 구조에 삽입 :

목록의 노드 달성하기 위해 코드를 추가합니다

완벽하게 다음과 같은 두 가지 상황을 달성하기 위해 노드 목록에 코드를 추가 단계 :

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index {
    [self rangeCheckForAdd:index];
    
    if (index == 0) {
        JKRSingleLinkedListNode *node = [[JKRSingleLinkedListNode alloc] initWithObject:anObject next:_first];
        _first = node;
    } else {
        JKRSingleLinkedListNode *prev = [self nodeWithIndex:index - 1];
        JKRSingleLinkedListNode *node = [[JKRSingleLinkedListNode alloc] initWithObject:anObject next:prev.next];
        prev.next = node;
    }
    
    _size++;
}
复制代码

부모 통합 구현의 동적 배열을 추가 할 때 검사 범위 인덱스.

노드가 추가되기 때문에, 단 하나의 삽입 동작하지만, 그 노드의 인덱스 위치를 찾고 수반 조회의 복잡성 때문에 O (N)의 노드의 복잡성을 추가하려면 O (N)이다.

노드 삭제

목록의 중간에 노드를 삭제하려면

삭제리스트 인덱스가 상정하고있는 노드 (1), 다음과 같이 :

만 노드 노드 변경 포인트를 기준으로 다음 포인터하기 전에 제거해야 다음 포인트는 노드의 노드를 삭제하기 위해, 노드는 대한 언급이 없기 때문에, 그것은 자동으로 복구됩니다 삭제됩니다 :

연결리스트 구조를 삭제합니다 :

목록 헤드 노드를 삭제

첫 번째 노드는 아래 목록을 삭제합니다 :

노드에 원래 노드로 _first 유일한 방법은 연결리스트의 헤드 포인터 :

연결리스트 구조를 삭제합니다 :

코드 구현의 노드 목록을 삭제하려면

다음과 같이 두 가지 경우 모두 요약하면, 삭제 코드의 목록입니다 :

- (void)removeObjectAtIndex:(NSUInteger)index {
    [self rangeCheckForExceptAdd:index];
    
    JKRSingleLinkedListNode *node = _first;
    if (index == 0) {
        _first = _first.next;
    } else {
        JKRSingleLinkedListNode *prev = [self nodeWithIndex:index - 1];
        node = prev.next;
        prev.next = node.next;
    }
    _size--;
}
复制代码

삭제 노드가 하나의 작업이 필요하지만, 인덱스 노드에서 찾고 포함하는 동안 추가 작업 노드로, 조회의 복잡도는 O (n)이, 그래서 삭제 된 노드의 복잡도는 O (N)입니다.

다른 기능에 관해서는 해당 목록을 나열하고, 마지막으로 소스 코드가없는, 등과 꼬리에 추가 또는 삭제 헤드 노드와 같은 여러 인터페이스를 구현하기 위해 위의 호출을 기반으로합니다.

그리고 동적 배열의 복잡성 대 시간

데이터 구조 동적 배열 단일 연결리스트
자세한 내역 가장 최악의 평균 가장 최악의 평균
어디 요소를 삽입 O (1) O (n) O (n) O (1) O (n) O (n)
어떤 위치의 요소를 삭제 O (1) O (n) O (n) O (1) O (n) O (n)
어떤 위치 요소를 교체 O (1) O (1) O (1) O (1) O (n) O (n)
어떤 위치 요소를 찾기 O (1) O (1) O (1) O (1) O (n) O (n)
마지막에 요소를 추가 O (1) O (n) O (1) O (n) O (n) O (n)
후행 요소 삭제 O (1) O (1) O (1) O (n) O (n) O (n)
머리에 요소를 추가 O (n) O (n) O (n) O (1) O (1) O (1)
헤더 요소 삭제 O (n) O (n) O (n) O (1) O (1) O (1)

상기 비교는 시간 복잡도에 의해 표현된다 :

  • 요소 어디서나 삽입 : 동적 배열 요소는 더 시간을 이동하고 머리에 가까이 이동해야합니다. 포인터 작업을 찾을 필요성에 대한 단일 연결리스트 노드가 수행되고, 꼬리 가까이 번 이상 찾습니다.
  • 어디 요소를 삭제 : 동적 배열 요소는 더 시간을 이동하고 머리에 가까이 이동해야합니다. 포인터 작업을 찾을 필요성에 대한 단일 연결리스트 노드가 수행되고, 꼬리 가까이 번 이상 찾습니다.
  • 대안 어딘가에 요소 : 직접적인 인덱스 동적 배열 위치와 값을 가지고, 오퍼랜드 1은 안정적이다. 포인터 작업을 찾을 필요성에 대한 단일 연결리스트 노드가 수행되고, 꼬리 가까이 번 이상 찾습니다.
  • 어디 요소를 찾기 : 동적 배열을 직접 인덱스 위치에 대한 값을 취함으로써, 피연산자 1은 안정적이다. 포인터 작업을 찾을 필요성에 대한 단일 연결리스트 노드가 수행되고, 꼬리 가까이 번 이상 찾습니다.
  • 꼬리에 요소를 추가 : 꼬리는 확장 동작이 존재하더라도, 동적 배열 인덱스 값은 상기 어레이의 대응하는 단부에 직접 첨가 될 수있는 추가, 여전히 다운 O 상각 (1). 스크래치 테일 노드로부터 단일 연결리스트 노드는 O (N)이고, 밝혀졌다.
  • 후단 소자 분리 : 어레이의 동적 단부 직접 어레이, 정착 동작의 종료에 대응하는 인덱스 값에 추가로 첨가 될 수있다. 스크래치 테일 노드로부터 단일 연결리스트 노드는 O (N)이고, 밝혀졌다.
  • 헤드에 요소를 추가 동적 배열은 이동 요소의 최대 개수를 요구 O (N)에 관한 것이다. 단일 연결 목록은 하나의 작업이 필요합니다.
  • 헤더 요소를 삭제 동적 배열은 이동 요소의 최대 개수를 요구하면 O (n)이된다. 단일 연결 목록은 하나의 작업이 필요합니다.

상기 분석은 최대가 될 수 있으며,이 체크리스트가 아닌 시간에 모든 경우 동적 배열의 복잡성 빈번한 삭제 요구와 어레이 헤드 부가 상기 단방향 링크리스트 우수한 동적 배열보다 낫다. 삭제하고 배열의 끝을 추가하는 자주 필요가 배열이 우수한 동적 인 방법 연결리스트 인 경우.

다음 테스트 :

헤드 삽입 및 삭제 동작, 동적 배열 및 비교 단일 연결 목록 10,000 :

삽입과 삭제 작업, 동적 배열 및 비교 단일 연결 목록 만 꼬리 :

그래서 더 나은 여전히 ​​다른 시나리오를 구별해야 단방향 연결리스트 특정 시간 복잡도에 그 동적 배열 안함. 당신이 자주 머리 배열 삽입을 필요로하고 작업을 삭제하면, 단방향 링크 목록은 동적 배열보다 훨씬 낫다. 배열의 끝에서 자주 삽입과 삭제가 필요하면, 동적 배열은 단방향 연결리스트보다 훨씬 낫다.

근원

소스 코드를 보려면 클릭하세요

추천

출처blog.csdn.net/weixin_34162401/article/details/91399651