stl原始碼剖析 詳細學習筆記 演算法(4)
//---------------------------15/03/31----------------------------
//lower_bound(要求有序)
template<class ForwardIterator, class T>
inline ForwardIterator lower_bound(ForwardIterator first,
ForwardIterator last,
const T& value)
{
return __lower_bound(first, last, value, distance_type(first),
iterator_category(first));
}
//採用二分法來尋找第一個允許插入的位置
template<class ForwardIterator, class T, class Distance>
ForwardIterator __lower_bound(ForwardIterator first,
ForwardIterator last,
const T& value, Distance*
forward_iterator_tag)
{
Distance len = 0;
//取到陣列大小len
distance(first, last, len);
Distance half;
ForwardIterator middle;
while (len > 0)
{
//找到中間的位置,取
//雖然取的是下界 比如len=3 取到half=1, first+1 就是第2個
half = len >> 1;
middle = first;
advance(middle, half);
if(*middle < value)
{
first = middle;
++first;
//first一開始指向 half+1的元素,所以右邊剩下的是 len-half-1
len = len - half - 1;
}
else
len = half;
}
return first;
}
//其實感覺沒有必要使用兩個版本,distance函式和advance函式底層就已經對迭代器進行分類運算了
//效率上應該不會差的。
template<class RandomAccessIterator, class T, class Distance>
RandomAccessIterator __lower_bound(RandomAccessIterator first,
RandomAccessIterator last,
const T& value, Distance*,
random_access_iterator_tag)
{
Distance len = last - first;
Distance half;
RandomAccessIterator middle;
while (len > 0)
{
half = len >> 1;
middle = first + half;
if(*middle < value)
{
first = middle + 1;
len = len - half - 1;
}
else
len = half;
}
return first;
}
//upper_bound(要求有序)
template<class ForwardIterator, class T>
inline ForwardIterator upper_bound(ForwardIterator first,
ForwardIterator last,
const T& value)
{
return __upper_bound(first, last, value, distance_type(first),
iterator_category(first));
}
template<class ForwardIterator, class T, class Distance>
ForwardIterator __upper_bound(ForwardIterator first,
ForwardIterator last,
const T& value, Distance*
forward_iterator_tag)
{
Distance len = 0;
//取到陣列大小len
distance(first, last, len);
Distance half;
ForwardIterator middle;
while (len > 0)
{
//和lower_bound不一樣,當 value 等於 middle 時是向右走的。所以指向
//的位置的值不是value,而是第一個大於value的值
half = len >> 1;
middle = first;
advance(middle, half);
if(value < *middle)
len = half;
else
{
first = middle;
++first;
len = len - half - 1;
}
}
return first;
}
template<class RandomAccessIterator, class T, class Distance>
RandomAccessIterator __upper_bound(RandomAccessIterator first,
RandomAccessIterator last,
const T& value, Distance*,
random_access_iterator_tag)
{
Distance len = last - first;
Distance half;
RandomAccessIterator middle;
while (len > 0)
{
half = len >> 1;
middle = first + half;
if(value < *middle)
len = half;
else
{
first = middle+1;
len = len -half -1;
}
}
return first;
}
//binary_search(要求有序)
template<class ForwardIterator, class T>
bool binary_search(ForwardIterator first, ForwardIterator last,
const T& value)
{
ForwardIterator i =lower_bound(first, last, value);
return i != last && !(value < *i);
//如果不存在,使用lower_bound獲得的*i > value;所以如果value < *i說明沒找到
}
template<class ForwardIterator, class T, class Compare>
bool binary_search(ForwardIterator first, ForwardIterator last,
const T& value, Compare comp)
{
ForwardIterator i = lower_bound(first, last, value, comp);
return i != last && !comp(value, *i);
}
//next_permutation
/*
下一個排列組合:
abc,acb,bac,bca,cab,cba。依次排序,前面的元素最遲改變,
把後面的都排序一遍,當前面的元素改變時,最後的元素要依次排序
acbd的 b<d,所以固定前面元素,得到acdb,再下一個 d>b c < d所以可以讓c 變成d 得到adbc
*/
template<class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first,
BidirectionalIterator last)
{
if(first == last)
return false;
BidirectionalIterator i = first;
++i;
if(i == last)
return false;
//區間沒有元素和只有一個元素都返回false;
i = last;
-- i;
//i=最後一個元素
for(;;)
{
//ii成了最後一個元素
BidirectionalIterator ii = i;
//i成了最後一個元素的前驅
--i;
//只要不是成倒序的就可以找到 *i < *ii,如果是倒序的說明沒有下一個排列組合了
if(*i < *ii)
{
/*
現在情況是 i d c... j 首先 d > c >... > j
i < d 。因為後面都是倒序的,我們要找到一個比i大一階的數填到i的位置。
所以while(!(*i < *--j)只要j小於等於i就左走,找到一個大於i的就可以把
這個數放入i的位置,把i放入j的位置。i放到j的位置。d開始到末尾的序列還是倒序的
所以要reverse( d c ... last)d就是ii在的位置
*/
BidirectionalIterator j =last;
while(!(*i < *--j));
iter_swap(i, j);
reverse(ii, last);
return true;
}
if(i == first)
{
//整個序列時倒序的,直接把它變成正序就好了。並要返回false
reverse(first, last);
return false;
}
}
}
//prev_permutation
template<class BidirectionalIterator>
bool prev_permutation(BidirectionalIterator first,
BidirectionalIterator last)
{
if(first == last)
return false;
BidirectionalIterator i = first;
++i;
if(i == last)
return false;
i = last;
--i;
//和next操作剛好相反,先找到一個數比他後驅大,再找到比他小一階的數交換,之後反轉
for(;;)
{
BidirectionalIterator ii = i;
--i;
if(*ii < *i)
{
BidirectionalIterator j =last;
while(!(*--j < *i));
iter_swap(i, j);
reverse(ii, last);
return true;
}
if(i == first)
{
reverse(first, last);
return false;
}
}
}
//random_shuffle
//對區間[first,last)隨機產生一個排列
template<class RandomAccessIterator>
inline void random_shuffle(RandomAccessIterator first,
RandomAccessIterator last)
{
__random_shuffle(first, last, distance_type(first));
}
template<class RandomAccessIterator, class Distance>
void __random_shuffle(RandomAccessIterator first,
RandomAccessIterator last,
Distance*)
{
if(first == last)
return;
for(RandomAccessIterator i =first + 1; i != last; ++i)
#ifdef __STL_NO_DRAND48
iter_swap(i, first + Distance(rand()%((i - first) + 1)));
#else
iter_swap(i, first + Distance(lrand48() % ((i - first) + 1)));
#endif
}
template<class RandomAccessIterator, class RandomNumberGenerator>
void random_shuffle(RandomAccessIterator first, RandomAccessIterator last,
RandomNumberGenerator& rand)
{
if(first == last)
return;
for(RandomAccessIterator i = first + 1; i != last; ++i)
iter_swap(i, first + rand((i - first) + 1));
}
//partial_sort
//基於堆來對前面部分資料進行排序
template<class RandomAccessIterator>
inline void partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last)
{
__partial_sort(first, middle, last, value_type(first));
}
template<class RandomAccessIterator, class T>
void __partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last,T*)
{
make_heap(first, middle);
for(RandomAccessIterator i = middle; i < last; ++i)
{
if(*i < *first)
__pop_heap(first, middle, i, T(*i), distance_type(first));
sort_heap(first, middle);
}
}
//sort
//Insetion Sort
template<class RandomAccessIterator>
void __insertion_sort(RandomAccessIterator first,
RandomAccessIterator last)
{
if(first == last)
return ;
for(RandomAccessIterator i =first + 1; i != last; ++i)
__linear_insert(first, i,value_type(first));
}
template<class RandomAccessIterator, class T>
inline void __linear_insert(RandomAccessIterator first,
RandomAccessIterator last, T*)
{
T value = *last;
//確保第一個元素是最小的
if(value < *first)
{
copy_backward(first, last, last + 1);
*first = value;
}
else
__unguarded_linear_insert(last, value);
}
template<class RandomAccessIterator, class T>
void __unguarded_linear_insert(RandomAccessIterator last, T value)
{
//插入排序,從尾部開始比較,原因是這樣正好可以邊比較邊把元素後移,
//不需要找到位置然後都後移一次。
RandomAccessIterator next = last;
--next;
//不用判斷越界,前面已經保證頭部是最小的了
while (value < *next)
{
*last = *next;
last = next;
--next;
}
*last = value;
}
//取中間值
template<class T>
inline const T& __median(const T& a, const T& b, const T& c)
{
if(a < b)
if(b < c)
return b; //a < b < c
else if(a < c)
return c; //a < b, b >= c, a<c
else
return a;
else if(a < c) //c > a >=b
return a;
elseif(b < c) // a >=b, a <= c, b < c
return c;
else
return b;
}
//很正常的快排劃分步驟最後得到的結果是 first後面包括first的值是大於等於pivot值的
//first前面的值是小於pivot值的
template<class RandomAccessIterator, class T>
RandomAccessIterator __unguarded_partition(RandomAccessIterator first,
RandomAccessIterator last,
T pivot)
{
while (true)
{
while (*first < pivot)
++first;
--last;
while(pivot < *last)
--last;
if(!(first < last))
return first;
iter_swap(first, last);
++first;
}
}
//真正的sort
template<class RandomAccessIterator>
inline void sort(RandomAccessIterator first,
RandomAccessIterator last)
{
if(first != last)
{
__introsort_loop(first, last, value_type(first), __lg(last - first)*2);
__final_insertion_sort(first, last);
}
}
template<class Size>
inline Size __lg(Size n)
{
Size k;
for(k = 0; n > 1; n >>= 1)
++k;
return k;
}
template<class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
RandomAccessIterator last, T*,
Size depth_limit)
{
//__stl_treshold 是全域性常數 為const int 16
while (last - first > __stl_threshold)
{
if (depth_limit == 0)
{
//如果呼叫深度到達限制就改呼叫堆排序
partial_sort(first, last, last);
return;
}
//深度減一
--depth_limit;
//呼叫一次劃分返回關鍵元素的迭代器
RandomAccessIterator cur = __unguarded_partition(
first, last, T(__median(*first,
*(first + (last - first) / 2),
*(last - 1))));
//對右邊進行迭代
__introsort_loop(cur, last, value_type(first), depth_limit);
last = cur;
}
}
template<class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last)
{
if (last - first > __stl_threshold)
{
__insertion_sort(first, first + __stl_threshold);
__unguarded_insertion_sort(first + __stl_threshold, last);
}
else
__insertion_sort(first, last);
}
template<class RandomAccessIterator>
inline void __unguarded_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last)
{
__unguarded_insertion_sort_aux(first, last, value_type(first));
}
template<class RandomAccessIterator, class T>
void __unguarded_insertion_sort_aux(RandomAccessIterator first,
RandomAccessIterator last,
T*)
{
for(RandomAccessIterator i = first; i != last; ++i)
__unguarded_linear_insert(i, T(*i));
}
/*
sort總結:先採用快排,有兩種情況產生:
1>深度沒有超出極限,會誕生一個個區間,每個區間大小小於等於__stl_threshold(預設為16),
然後對前16個採用插入排序,需要判斷尾元素是否小於first元素。這次呼叫完就確保first是最小的
然後再呼叫__unguarded_linear_sort就可以少一個判斷,也就可以從first + __stl_threshold
的地方進行開始呼叫__unguared_linear_sort,插入位置會一直往左,有可能會越過first + __stl_threshold
的位置。
(ps:一開始我想不明白的一點是,如果先對前16個元素呼叫一次__unguarded_linear_insert,那如果當初劃分時
前面13個(只要小於16就行)是一個區間,那不是會把後面的3個元素牽扯進來,如果後面的3個元素不是最小的三個
那排序不就失敗了,我當時想的是final sort那呼叫__unguarded_linear_insert(first +__stl_threshold, last)
會以first +__stl_threshold為first區間,對之後的所有元素進行排序,會造成一個問題,前16箇中有比後面
大的元素。後來才發現sgi的奇妙設計,那個while (value < *next),並沒有越界判斷,所以會一直往左搜尋。)
2>迭代深度超出限制,會對之後迭代的區間進行堆排序,這時剩下的區間就是不確定的,有已經排序好的(深度超出限制),
也有沒排序的(快排迭代達到16個元素的),再次呼叫插入排序,對所有區間整理一遍。
*/
//equal_range(要求有序)
//返回由等於傳入值的元素組成的區間
template<class ForwardIterator, class T>
inline pair<ForwardIterator, ForwardIterator>
equal_range(ForwardIterator first, ForwardIterator last,
const T& value)
{
return __equal_range(first, last, value, distance_type(first),
iterator_category(first));
}
template<class RandomAccessIterator, class T, class Distance>
pair<RandomAccessIterator, RandomAccessIterator>
__equal_range(RandomAccessIterator first, RandomAccessIterator last,
const T& value, Distance*, random_access_iterator_tag)
{
Distance len = last - first;
Distance half;
RandomAccessIterator middle, left, right;
while (len > 0)
{
half = len >> 1;
middle = first + half;
if(*middle < value)
{
first = middle + 1;
len = len - half -1;
}
else if(value < *middle)
len = half;
else
{
left = lower_bound(first, middle, value);
right = upper_bound(++middle, first + len, value);
return pair<RandomAccessIterator, RandomAccessIterator>(left, right);
}
//因為lower_bound和upper_bound都會呼叫同樣的步驟直到相等。
}
return pair<RandomAccessIterator, RandomAccessIterator>(first, first);
//在沒有value值的情況下,返回一個區間[first,first)也就是first=last的情況,這樣可以表示
//沒有相應元素。
}
template<class ForwardIterator, class T, class Distance>
pair<ForwardIterator, ForwardIterator>
__equal_range(ForwardIterator first, ForwardIterator last,
const T& value, Distance*, forward_iterator_tag)
{
Distance len = last - first;
Distance half;
ForwardIterator middle, left, right;
while (len > 0)
{
half = len >> 1;
middle = first;
advance(middle, half);
if(*middle < value)