從STL代碼(3.3版,我認爲)是這樣的:
template <class _RandomAccessIter, class _Tp>
void __nth_element(_RandomAccessIter __first, _RandomAccessIter __nth,
_RandomAccessIter __last, _Tp*) {
while (__last - __first > 3) {
_RandomAccessIter __cut =
__unguarded_partition(__first, __last,
_Tp(__median(*__first,
*(__first + (__last - __first)/2),
*(__last - 1))));
if (__cut <= __nth)
__first = __cut;
else
__last = __cut;
}
__insertion_sort(__first, __last);
}
讓我們簡化一下:
template <class Iter, class T>
void nth_element(Iter first, Iter nth, Iter last) {
while (last - first > 3) {
Iter cut =
unguarded_partition(first, last,
T(median(*first,
*(first + (last - first)/2),
*(last - 1))));
if (cut <= nth)
first = cut;
else
last = cut;
}
insertion_sort(first, last);
}
我做什麼這裏是去除雙下劃線和_Uppercase東西,這只是爲了保護用戶可以合法定義爲宏的代碼。我還刪除了最後一個參數,該參數僅用於模板類型推導,並且爲了簡潔起見將其重命名爲迭代器類型。
正如您現在應該看到的那樣,它會重複劃分範圍,直到剩餘範圍內剩餘的元素少於四個,然後對其進行簡單排序。
現在,爲什麼是O(n)?首先,最多三個元素的最終排序是O(1),因爲最多三個元素。現在,剩下的是重複分區。分區本身是O(n)。儘管如此,每一步都會減少下一步需要觸及的元素的數量,因此您有O(n)+ O(n/2)+ O(n/4)+ O(n/8),這就是小於O(2n),如果你總結。由於O(2n)= O(n),因此平均具有線性複雜性。
您是否注意到根據cppreference,算法在平均情況下只應該是'O(n)'。它沒有聲明最壞的情況。這意味着快速選擇將是可行的,因爲它平均具有「O(n)」。 – Nobody 2015-03-20 09:05:08
@沒有人可以指出除了使用Introselect以外的東西可能不是最壞的情況* O(n)*。維基百科和Introselect論文聲稱Introselect在*最糟糕的情況下是* O(n)*。 – 2015-03-20 11:22:08
正如你所說,introselect是快速選擇和中位數的組合。 QuickSelect在平均和最好的情況下速度非常快,但是最差的情況是二次方,而中位數的中位數保證是總是線性時間算法的稍慢。 Introselect通過快速選擇嘗試快速運行,如果不能運行,則會回退到速度較慢但保證的線性時間算法,從而限制其最壞情況運行時間,使其在變得比線性更差之前。也許你應該澄清一下你的問題,因爲看起來你對這個問題有疑惑:STL,Introsort,Complexities? – Nobody 2015-03-20 12:02:14