가장 효율적인 상수 공간 정렬 알고리즘은 무엇입니까?


19

배열 크기 이외의 바이트를 할당하지 않고 int 배열에 대한 정렬 알고리즘을 찾고 있는데 두 가지 명령으로 제한됩니다.

  1. 스왑 : 다음 인덱스를 현재 인덱스로 교체합니다.

  2. MOVE : 커서를 +1 또는 -1 색인으로 이동합니다.

즉, 비 이웃 인덱스를 교환,도 인덱스를 바꿀 수 없다 100당신은 그냥 인덱스를 교환 한 후, 10. 가장 효율적인 알고리즘, 즉 적은 총 이동량을 사용하는 알고리즘은 무엇입니까?


13
그렇게 이상하지는 않지만 롤업 된 테이프에 붙어있는 카트 목록을 정렬하는 물리적 인 기계입니다. 기계는 테이프를 앞뒤로 만 움직일 수 있으며 인접한 카드 만 교체 할 수 있습니다. 현실 세계에서는 순간 이동할 수 없으므로 제한이 있습니다.
MaiaVictor

2
따라서 배열의 크기 이외의 바이트를 할당하지 않는 알고리즘을 원할 때 요소 저장소 만 참조한다고 생각합니까? 여전히 카운터 등을 할당 할 수 있습니까?
Darkhogg

5
그렇지. 물론이야. 추가 구조를 할당 할 수 있습니다. 전체 배열을 할당하고 많은 계산을 수행 할 수 있으며 비용은 0입니다. 최소화해야하는 유일한 것은 실제 물리적 시스템의 SWAP / MOVE 수입니다. 속도가 느리기 때문입니다. 기포 정렬이 내가 할 수있는 최선이지만, 더 나은 옵션이 있어야한다고 생각했습니다.
MaiaVictor

1
나는 그런 알고리즘이 없다고 생각합니다. 없이 어떤 추가 메모리, 당신은 어떤 제어 상태를 저장하는 방법이 없습니다 것입니다.
Raphael

1
@ svrm : 예, 무제한 RAM과 테이프를 RAM에 복사하고 무료로 임의의 계산을 수행 할 수있는 기능으로 "모든 것을 시도하고 가장 잘 적용하십시오"라는 알고리즘이 테이프의 이동 횟수 측면에서 최적입니다. 실용적이지는 않지만 실제로는 런타임이 0이 아닌 몇 년이 걸리기 때문입니다. ;-) 길이 N의 테이프를 RAM에 복사하는 데 N 이동 비용이 소요되면 순진한 무차별 대입은 최적이 아니지만 N 내에 있습니다. 최적의. 그러나 이것의 어느 것도 당신의 문제에만 국한된 것이 아닙니다. 이런 방식으로 언급 될 때 많은 문제는 가짜 알고리즘을 사용하여 "오프라인"으로 해결 될 수 있습니다.
Steve Jessop

답변:


13

버블 쉐이커 의 양방향 버전 인 칵테일 셰이커 정렬을 고려하십시오 . 거품 정렬을 낮음에서 높음으로 설정 한 다음 거품 정렬을 높임에서 낮음으로 설정하고 완료 될 때까지 반복합니다. 이것은 여전히 이지만 어레이의 하이 엔드 근처에있는 작은 요소가 N 패스가 아닌 단일 패스에서 최종 위치로 이동하기 때문에 평균적으로 패스가 훨씬 적습니다. 또한 스왑이 발생한 최저 및 최고 위치를 추적 할 수 있습니다. 후속 패스는 해당 포인트를 넘어 스캔 할 필요가 없습니다.영형(2)


4

배열을 주문하는 데 필요한 인접 요소의 스왑 수는 배열의 반전 수와 같습니다. 총 n 개의 요소를 갖는 경우 최대 n * (n-1) / 2 개의 반전이 있으므로 기포 정렬은이 모델에서 점진적으로 최적의 스왑 수를 제공합니다.


실제로 버블 정렬은 최적의 스왑 수를 정확하게 제공합니다. 그러나 각 순열마다 최적의 스왑 수를 수행하는 여러 가지 방법이 있으며, 총 이동 수를 줄이는 방법은 확실하지 않습니다. (거품 정렬로 말하면 "정렬되지 않은 가장 큰 분류를 선택하여 정렬 끝으로 이동")
Peter Kravchuk

4

영형(2)

+

부울 플래그를 사용하여 요소를 스왑했는지 여부를 알지 못하는 알고리즘은 다음과 같습니다 (정보를 메모리가 아닌 머신 상태로 유지하는 트릭).

Start:
    Do until we are not at the leftmost position (Op 4)
        move left (Op 2b)

Check:
    If we are at rightmost position (Op 3)
        goto Finished:
    If current value is larger than next value (Op 5)
        goto Unfinished:
    move right (Op 2a)
    Repeat Check:

Unfinished:
    If we are at rightmost position (Op 3)
        goto Start:
    If current value is larger than next value (Op 5)
        swap the elements (Op 1) and move right (Op 2a)
    Repeat Unfinished:

Finished:
    The list is sorted now, output it.

그놈 정렬 인 Eric Lippert의 솔루션은 기본적으로 양방향 버블 정렬이기 때문에 작동합니다.


삽입 정렬은 어떻습니까?
Darkhogg

기포 정렬에는 이미 허용 된 것보다 더 많은 최소 2 개의 루프 카운터가 필요합니다.
Raphael

1
아니요, 카운터를 사용하지 않고 변경이 없을 때까지 (최대 n 회) 왼쪽에서 오른쪽으로, 오른쪽에서 왼쪽으로 이동할 수 있습니다. 변경 사항이 있으면 부울 플래그를 기록하기 위해 추가 공간이 필요하지 않습니다. 변경이 있으면 다른 서브 루틴 인 것을 제외하고는 동일한 서브 루틴으로 이동하십시오.
Shreesh

1
물론, 나는 양쪽 끝에서 공백을 읽을 수 있다고 가정하므로 목록의 시작 또는 끝임을 알 수 있습니다. 또한 현재 요소와 다음 요소를 모두 읽어서 교체해야하는지 알 수 있다고 가정합니다.
Shreesh

1
또는 연산자 스왑을 "오름차순이 아닌 경우 스왑"으로 수정하는 경우.
Shreesh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.