정렬 된 배열에 요소 추가


31

(실제적인 문제뿐만 아니라 알고리즘 관점에서) 가장 빠른 방법은 무엇입니까?

다음 줄을 따라 뭔가를 생각하고있었습니다.

배열의 끝에 추가 한 다음 bubblesort를 사용하여 가장 가까운 경우 (시작시 완전히 정렬 된 배열)를 가지고 선형 실행 시간 (가장 좋은 경우)을 갖습니다.

반면에 정렬 된 배열로 시작한다는 것을 알면 이진 검색을 사용하여 주어진 요소의 삽입 지점을 찾을 수 있습니다.

내 직감은 두 번째 방법이 거의 최적이지만 거기에 무엇이 있는지 궁금합니다.

어떻게 최선을 다할 수 있습니까?


1
자주해야하는 경우 가장 빠른 방법은 처음에 배열을 사용하지 않는 것입니다.
reinierpost

자체 균형 이진 트리를 의미합니까?
soandos

그렇습니다. 답변을 참조하십시오 ...
reinierpost

답변:


25

배열 요소 읽기 및 쓰기 수를 계산합니다. 버블 정렬을 수행하려면 액세스 가 필요 합니다 (최초의 쓰기가 끝났으며 최악의 경우 n 개의 스왑 을 수행하기위한 2 개의 읽기 및 2 개의 쓰기 ). 이진 검색을 수행하려면 2 log n + 2 n + 1 ( 이진 검색의 경우 2 log n , 최악의 경우 배열 요소를 오른쪽으로 이동하려면 2 n , 배열 요소를 쓰려면 1)이 필요합니다. 올바른 위치).1+4nn2logn+2n+12logn2n

따라서 두 방법 모두 배열 구현에 대해 동일한 복잡성을 갖지만 이진 검색 방법은 장기적으로 무조건 절반의 배열 액세스가 더 적습니다. 자연스럽게 작용하는 다른 요소가 있습니다.

실제로, 더 나은 구현을 사용하고 실제 배열 액세스 만 계산할 수 있습니다 (삽입 할 요소에 대한 액세스는 아님). 당신은 할 수있는 종류의 버블 및 로그 N + 2 , N + 1 이진 검색을위한 ... 그래서 레지스터 / 캐시 액세스가 저렴하고 배열 액세스가 끝에서 검색하고 길을 따라 이동, 비싼 경우 (영리를 삽입을위한 거품 정렬)이 더 좋을 수는 있지만 무증상 일 수도 있습니다.2n+1logn+2n+1

더 나은 솔루션은 다른 데이터 구조를 사용하는 것입니다. 배열은 O (1) 액세스 (임의 액세스)를 제공하지만 삽입 및 삭제 비용이 발생할 수 있습니다. 해시 테이블에는 O (1) 삽입 및 삭제가있을 수 있으며 액세스 비용이 발생합니다. 다른 옵션으로는 BST 및 힙 등이 있습니다. 삽입, 삭제 및 액세스에 대한 응용 프로그램의 사용 요구 사항을 고려하고보다 특수한 구조를 선택하는 것이 좋습니다.

개의 요소 를 n 개의 정렬 된 배열에 추가 하려면 m 개의 항목 을 효율적으로 정렬 한 다음 두 배열을 병합 하는 것이 좋습니다 . 또한 정렬 된 배열은 힙 (힙 정렬) 등을 사용하여 효율적으로 구축 할 수 있습니다.mnm


1
"해시 테이블에 O (1) 삽입 및 삭제가있을 수 있습니다."
Raphael

8
상각 예상 .
JeffE

BST에는 검색 및 삽입 (wikipedia)에 가 있으므로 여기에서 가장 권장되지 않는 이유는 무엇입니까? 검색하고 삽입하려면 O ( 2 l o g n ) 를 입력하십시오. O(log n)O(2 log n)
Kashyap

8

힙을 사용하지 않는 이유가 있으면 Bubble Sort 대신 Insertion Sort를 사용하십시오. 정렬되지 않은 요소가 몇 개있을 때 더 좋습니다.


7

배열을 사용하고 있기 때문에 항목을 삽입하는 데 비용이 듭니다. 예를 들어 배열 중간에 무언가를 추가 할 때 배열이 정렬 된 상태로 유지하려면 모든 요소를 ​​한 칸씩 이동해야합니다 .O(n)

항목을 넣을 위치를 찾는 가장 빠른 방법은 이진 검색이므로 언급 한 것처럼 총 복잡도는 O ( n + lg n ) 입니다. O ( n ) .O(lgn)O(n+lgn)O(n)

즉, 내가 특히 울퉁불퉁하다고 생각되면 에서 정렬 된 배열에 추가 할 수 있다고 주장 할 수 있습니다 . 설명은 배열이 새 요소를 삽입 한 후 정렬 상태를 유지해야합니다.O(1)

어쨌든,이 문제에 대해 거품 정렬을 꺼낼 이유가 없습니다.


2
O

으르렁 거리기 위해 +1 .. :-)
Kashyap

4

Patrick87은이 모든 것을 잘 설명했습니다. 그러나 한 가지 추가 최적화는 순환 버퍼와 같은 것을 사용하는 것입니다. 평소처럼 삽입 된 요소의 위치에서 오른쪽으로 항목을 이동할 수 있습니다. 그러나 올바른 위치의 왼쪽으로 항목을 왼쪽으로 이동할 수도 있습니다. 이렇게하려면 배열을 원형으로 처리해야합니다. 즉, 마지막 항목이 첫 번째 항목 바로 앞에 있으며 항목이 현재 시작되는 위치에 색인을 유지해야합니다.

이렇게하면 약 절반의 배열 액세스를 수행 할 수 있습니다 (삽입하는 인덱스의 균일 한 분포를 가정). 위치를 찾기 위해 이진 검색을 수행하는 경우 왼쪽 또는 오른쪽으로 이동할지 여부를 선택하는 것은 쉽지 않습니다. 버블 정렬의 경우 시작하기 전에 올바르게 "추측"해야합니다. 그러나 그렇게하는 것은 간단합니다. 삽입 된 항목을 배열의 중앙값과 비교하면 단일 배열 액세스로 수행 할 수 있습니다.


4

이 문제에 대해 삽입 정렬 알고리즘을 효과적으로 사용했습니다 . 한 번에 우리는 해시 테이블 개체에 성능 문제가 있었으므로 성능을 크게 향상시키는 대신 이진 검색을 사용하는 새 개체를 작성했습니다. 목록을 정렬 상태로 유지하려면 검색 요청으로 인해 목록을 정렬해야 할 때 마지막 정렬 이후에 추가 된 항목 수 (즉, 정렬되지 않은 항목 수)를 추적합니다. 삽입 정렬 또는 빠른 정렬에 따라 분류되지 않은 항목의 비율. 삽입 정렬을 사용하는 것이 성능 향상에 핵심이었습니다.


상각 된 운영 비용과 관련하여 공식적인 결과가 있습니까? 그리고 : 환영합니다!
Raphael
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.