병합 정렬에서 "분할"단계를 피할 수 있습니까?


13

정렬 병합

따라서 병합 정렬은 나누기 및 정복 알고리즘입니다. 위의 다이어그램을 보면서 기본적으로 모든 나누기 단계를 무시할 수 있는지 생각했습니다.

2만큼 점프하면서 원래 배열을 반복하면 인덱스 i 및 i + 1에서 요소를 가져 와서 자체 정렬 배열에 넣을 수 있습니다. 이러한 하위 배열을 모두 갖추면 (그림에 표시된대로 [7,14], [3,12], [9,11] 및 [2,6]) 일반 병합 루틴을 계속 진행할 수 있습니다. 정렬 된 배열

배열을 반복하고 필요한 하위 배열을 즉시 생성하는 것이 분할 단계를 전체적으로 수행하는 것보다 덜 효율적입니까?


답변:


29

혼란은 알고리즘 의 개념적인 설명과 그 구현 사이의 차이에서 발생합니다 .

논리적 병합 정렬은 배열을 더 작은 배열로 분할 한 다음 다시 병합하는 것으로 설명됩니다. 그러나 "배열 분할"은 "메모리에 완전히 새로운 배열을 생성"또는 이와 유사한 것을 의미하지는 않습니다. 코드에서 다음과 같이 구현할 수 있습니다.

/*
 * Note: array is now split into  [0..n) and [n..N)
 */

즉, 실제 작업이 수행되지 않으며 "분할"은 순전히 개념입니다. 그래서 당신이 확실히 제안하는 것은 작동하지만 논리적으로 여전히 배열을 "분할"하고 있습니다-컴퓨터에서 할 일이 필요하지 않습니다 :-)


4
개인적으로 나는 상향식 병합 정렬을 좋아합니다. 각 재귀 수준에서 임시 버퍼를 할당하지 않는 방식으로 구현하는 것이 더 간단하기 때문입니다. 대신 버퍼를 한 번 할당하고 그 사이에 탁구를 할당합니다.
ratchet freak

이 계산은 계산 상 no-op입니다 ... 플러스 OP 제안은 단일 요소 배열의 병합과 동등한 기능을 소개하고 2 단계에서 병합을 사용하기 시작합니다. 원래 병합도 잘 작동하기 때문에 중복되는 것처럼 보입니다. 이를 최적화 할 필요는 없습니다. 중복 개념과 논리 만 소개합니다.
luk32

@ratchetfreak : 나도 그것을 좋아하지만 슬프게도 하향식 (적어도 내가 알고있는 버전)과 동일하지 않습니다. 병합을 다르게 수행합니다. 기본적으로 다음 2의 제곱의 배열 길이로 반올림합니다. 이는 조금 느릴 수도 있습니다. 다른 곳에서 막대한 비용을 들이지 않고 정확히 동일한 병합을 수행하는 상향식 버전을 알고 있습니까?
user541686

@Mehrdad의 유일한 실제 문제는 병합해야 할 작은 꼬리입니다. 최악의 경우 길이 배열의 단일 항목으로 병합 할 다른 패스를 의미 1<<n+1합니다. 너무 작은 꼬리가 낮은 패스에 병합되도록 물건을 조정할 수 있다고 확신합니다.
ratchet freak

@psmears "당신은 그렇게하기 위해 컴퓨터에서 어떤 작업을 할 필요가 없습니다"– 일부 재귀 분할 함수 (예제 ​​다이어그램에서 7 번의 호출)의 n 번 호출의 성능 비용 은 기본적으로 무시할 만하다고 생각합니다.
Jimmy_Rustle

11

나는 당신이 의미하는 바는 상향식 구현 이라고 생각한다 . 상향식 구현에서는 단일 셀 요소에서 시작하여 요소를 더 큰 정렬 된 목록 / 배열로 병합하여 위쪽으로 이동합니다. 가운데 배열, 즉 한 요소 배열에서 시작하여 위 그림의 화살표를 뒤집으십시오.

또한 배열이 일정한 크기에 도달 할 때까지 배열을 나눔으로써 병합 정렬최적화 할 수 있습니다 . 그런 다음 삽입 정렬과 같이 단순히 정렬합니다.

그렇지 않으면 배열을 나누지 않고 정렬 할 수 없습니다. 실제로 Merge 정렬의 요점은 하위 배열, 즉 나누기 및 정복을 나누고 정렬하는 것입니다.

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