실행중인 중앙값을 계산해야합니다.
입력 : , k , 벡터 ( x 1 , x 2 , … , x n ) .
출력 : 벡터 , 여기서 y i 는 ( x i , x i + 1 , … , x i + k - 1 ) 의 중앙값입니다 .
(근사치로 부정 행위 없음; 정확한 솔루션을 원합니다. 요소 는 큰 정수입니다.)
크기의 검색 트리를 유지하는 사소한 알고리즘이 있습니다 . 총 실행 시간은 O ( n log k ) 입니다. 여기서 "검색 트리"는 로그 시간에 삽입, 삭제 및 중앙 쿼리를 지원하는 효율적인 데이터 구조를 나타냅니다.
그러나 이것은 나에게 약간 바보처럼 보입니다. 우리는 중앙값뿐만 아니라 크기가 k 인 모든 창 내에서 모든 주문 통계를 효과적으로 학습 합니다 . 또한, 특히 k 가 큰 경우 (실제로 큰 검색 트리가 느리거나 메모리 소비 오버 헤드가 크지 않으며, 캐시 효율성이 좋지 않은 경우 등) 이는 실제로 매력적이지 않습니다 .
실질적으로 더 나은 것을 할 수 있습니까?
하한이 있습니까 (예 : 사소한 알고리즘이 비교 모델에 대해 무조건 최적입니까?)?
편집 : David Eppstein은 비교 모델에 대한 좋은 하한을 제공했습니다! 그럼에도 불구하고 사소한 알고리즘보다 약간 더 영리한 것을 할 수 있는지 궁금합니다.
예를 들어, 다음 선을 따라 무언가를 수행 할 수 있습니다. 입력 벡터를 크기가 부분으로 나눕니다 . 각 부분을 정렬합니다 (각 요소의 원래 위치를 추적 함). 그런 다음 부분적으로 정렬 된 벡터를 사용하여 보조 데이터 구조없이 효율적으로 실행중인 중앙값을 찾으십시오. 물론 이것은 여전히 O ( n log k ) 이지만 실제로 정렬 정렬은 검색 트리를 유지 관리하는 것보다 훨씬 빠른 경향이 있습니다.
편집 2 : Saeed는 정렬이 검색 트리 작업보다 빠른 이유를 알고 싶었습니다. 다음은 매우 빠른 벤치 마크입니다. , n = 10 8 :
- ≈ 8s : 각각 k 개의 요소로 벡터 정렬
- s 10s : 요소 로 벡터 정렬
- s 80s : k 크기의 해시 테이블에서 삽입 및 삭제
- 390 390s : k 크기의 균형 검색 트리에서 삽입 및 삭제
해시 테이블은 비교를 위해 존재합니다. 이 응용 프로그램에서 직접 사용되지 않습니다.
요약하면 정렬 성능과 균형 검색 트리 작업의 성능에 거의 50 배의 차이가 있습니다. 를 늘리면 상황이 훨씬 나빠집니다 .
(기술 세부 사항 : 데이터 = 임의의 32 비트 정수. 컴퓨터 = 일반적인 최신 랩톱) 테스트 코드는 표준 라이브러리 루틴 (std :: sort) 및 데이터 구조 (std :: multiset, std ::를 사용하여 C ++로 작성되었습니다. unsorted_multiset) 두 개의 다른 C ++ 컴파일러 (GCC와 Clang)와 두 개의 다른 표준 라이브러리 구현 (libstdc ++ 및 libc ++)을 사용했습니다.