c++ algorithm 的用法

时间:2022-09-25 17:18:08
1 , accumulate()
template<class _II, class _Ty> inline
_Ty accumulate(_II _F, _II _L, _Ty _V)
{for (; _F != _L; ++_F)
_V = _V + *_F;
return (_V); }
作用就是计算累积.
2,adjacent_difference()
_OI _Adjacent_difference(_II _F, _II _L, _OI _X, _Ty *)
{_Ty _V = *_F;
for (*_X = _V; ++_F != _L; )
{_Ty _Tmp = *_F;
*++_X = _Tmp - _V;
_V = _Tmp; }
return (++_X); }
就是计算连续两个结点之间的差值的,然后存储到另一个容器里面.
这个用法一定要明白是怎么回事,比如
int a[10] = {0};
for(int i=0; i<10; ++i)
{
a[i] = i;
}
int b[10];
addjacent_difference(a, a+10, b);
cout<<b[10]<<endl;
这个值存在b[10]里面
刚才对这个b[10]有些疑问,实在感觉到自己经验有问题的了,确实是太少的了.问了量子,得到的回答是这个是合法的,只要不超出段.推荐了<C专家编程>,看来,应该抽时间来看看的了.
3, find_adjacent()
这个函数写的比较好的了.
find_adjacent(iterator first, iterator end)
{
for(iterator fb; (fb=first)!=end && ++first!=end;)
{
if(*fb==*first)
return fb;
}
}
函数写的比较简捷,看着比较舒服.:
4, copy()和copy_backward()
_BI2 copy_backward(_BI1 _F, _BI1 _L, _BI2 _X)
{while (_F != _L)
*--_X = *--_L;
return (_X); }

一遍循环复制, 唯一要注意的就是copy_backward()的用法:
copy_n()
这个是某些STL的扩展,在标准里面没有定义
5 count(), count_if()
第二个函数有个例子比较有趣,
count_if(a, a+10, bind2nd(equal_to<int>, 0));
struct equal_to : binary_function(class A, class B, class result)

6 equal()
这个equal(first1, end1, first2)
{
return (mismatch(first1, end1, first2).first==end1);
}
mismatch(first1, end1, first2)
{
for(; first1!=end1 && *first1==*first2; ++first1, first2);

return pair<key1, key2>(first1, first2);
}
equal_range()
7, fill(), fill_n()
比较简单,就不说了.
8, find(), find_end(), find_first_of, find_if(), for_each()
这个能注意的就是怎么利用这个函数来查找所有的给定值.注意用法就好.了
9,generate() generate_n() 注意,第二个是运行几个元素,不是运行几次,
10, includes()注意的就是那个需要是排序排过序的,并且是升序.
inner_product的使用,
inplace_merge()
其实这个算法也很巧妙的了,给出了两个有序数组的比较方法,基本思想是这样的,
一个数组分为两段,第一段长为D1,第二段长为D2,当然D1是前面的一段. 这时候,如果D1>D2,那么就把D1的内容复制到一个和D1一样大小的数组里,然后从头排序,如果D2长的话,同样也要从建一个D2长的数组,把第二段复制进去,然后从后面开始排序.
这个用到的是merge()算法的,不同的是merge()把排过序的结果放到新的数组,而inplace_merge()是在原数组内排序.

11, is_heap()在标准STL里面没有实现.
is_sorted()没有实现
push_heap()
pop_heap() 看下面的解释吧.
12 , iter_swap()
13, lexicographical_compare()
lexicographical_compare_3way()掌握这两个用法.
14, lower_bound()使用提binary_search()
15, make_heap(), 生成的是最大值堆.
void _Make_heap(_RI _F, _RI _L, _Pd *, _Ty *)
{_Pd _N = _L - _F;
for (_Pd _H = _N / 2; 0 < _H; )
--_H, _Adjust_heap(_F, _H, _N, _Ty(*(_F + _H))); }
最主要的是一定要注意的是从哪里开始调整的,是从N/2这个位置开始的,因为,叶子点是内点的1/2;
16, max(), min(), max_element(), min_element()就不说了解.
唯一不同的是max, min返回的是值,max_element, min_element()返回的是指针.

17, mismatch() 返回第一个不相同的元素.
18, next_permutation() 生成排列.这个是好函数,要搞明白它.看它的算法是怎么实现的.
这个算法比较好,可是说是和那个链表排序是一样的迷人.一定要实现一下.

bool next_permutation(_BI _F, _BI _L)
{_BI _I = _L;
if (_F == _L || _F == --_I)
return (false);
for (; ; )
{_BI _Ip = _I;
if (*--_I < *_Ip)
{_BI _J = _L;
for (; !(*_I < *--_J); )
;
iter_swap(_I, _J);
reverse(_Ip, _L);
return (true); }
if (_I == _F)
{reverse(_F, _L);
return (false); }}}
19, nth_element()
函数功能如下.
put one element in its sorted location and make sure that no elements to its left are greater than element to its right.
这个函数先判别这个n是多大,如果大于16,那么使用快排,否则使用插入排序..
"
void _Nth_element(_RI _F, _RI _Nth, _RI _L, _Ty *)
{for (; _SORT_MAX < _L - _F; )
{_RI _M = _Unguarded_partition(_F, _L, _Median(_Ty(*_F),
_Ty(*(_F + (_L - _F) / 2)), _Ty(*(_L - 1))));
if (_M <= _Nth)
_F = _M;
else
_L = _M; }
_Insertion_sort(_F, _L); }

这个应该比较清楚的了.
20, partial_sort()
使用的就比较巧妙的了,使用堆排序,"+
void _Partial_sort(_RI _F, _RI _M, _RI _L, _Ty *)
{make_heap(_F, _M);
for (_RI _I = _M; _I < _L; ++_I)
if (*_I < *_F)
_Pop_heap(_F, _M, _I, _Ty(*_I), _Dist_type(_F));
sort_heap(_F, _M); }
void _Pop_heap(_RI _F, _RI _L, _RI _X, _Ty _V, _Pd *)
{*_X = *_F;          //把最大值放到I位置
_Adjust_heap(_F, _Pd(0), _Pd(_L - _F), _V); }

void _Adjust_heap(_RI _F, _Pd _H, _Pd _N, _Ty _V)
{_Pd _J = _H;  //去最大值后,调整子结点,放到最大值
_Pd _K = 2 * _H + 2;
for (; _K < _N; _K = 2 * _K + 2)
{if (*(_F + _K) < *(_F + (_K - 1)))
--_K;
*(_F + _H) = *(_F + _K), _H = _K; }
if (_K == _N)   //因为取的是右结点,有一种情况是,最后最右结点时候,却出了边界.
*(_F + _H) = *(_F + (_K - 1)), _H = _K - 1;
_Push_heap(_F, _H, _J, _V); }
//把要插入的值放到最后一个位置,然后向上推,一直找到要插入的位置
void _Push_heap(_RI _F, _Pd _H, _Pd _J, _Ty _V)
{for (_Pd _I = (_H - 1) / 2; _J < _H && *(_F + _I) < _V;
_I = (_H - 1) / 2)
*(_F + _H) = *(_F + _I), _H = _I;
*(_F + _H) = _V; }

可以看到先用堆排M以前的,然后查找M后面的,看哪些比堆里面最大的那个小,那么就把那个最大值给POP出去,因为这个最大值是肯定不会在前M个里面,现在看一下,POP_heap()怎么实现.

21, partition()
这个算法就是和快速排序的那个是一样的,从两头开始,向中间逼近.
22,power()
这个没有实现.
23, prev_permutation()
这个记住和那个next_permatation()的算法就OK了.
24, ramdom_sample(),
random_sample randomly copy elements from one range to another
random_sample_n sample N random elements from a range
25, remove()
这是在酷讯的一问题,就是说remove执行了什么操作.
这个操作是这样的,就是从范围之内, ,删除那些等于某值的数,把后面的值,住前面调比如 说0 0 2 0 2 0 0 经过 remove() 0 之后,会变成2 2 2 2 2 0 0
_OI remove_copy(_II _F, _II _L, _OI _X, const _Ty& _V)
{for (; _F != _L; ++_F)
if (!(*_F == _V))
*_X++ = *_F;
return (_X); }

_FI remove(_FI _F, _FI _L, const _Ty& _V)
{_F = find(_F, _L, _V);
if (_F == _L)
return (_F);
else
{_FI _Fb = _F;
return (remove_copy(++_F, _L, _Fb, _V)); }}
remove()执行的是remove_copy()函数,
这里也就不说了.现在感觉,用remove_copy()更好一些的.
remove remove elements equal to certain value
remove_copy copy a range of elements omitting those that match a certian value
remove_copy_if create a copy of a range of elements, omitting any for which a predicate is true
remove_if remove all elements for which a predicate is true

27:
replace replace every occurrence of some value in a range with another value
replace_copy copy a range, replacing certain elements with new ones
replace_copy_if copy a range of elements, replacing those for which a predicate is true
replace_if change the values of elements for which a predicate is true
这几个函数,和remove()差不多的,不过,应该更好理解一些.
reverse reverse elements in some range
reverse_copy create a copy of a range that is reversed
28,
rotate move the elements in some range to the left by some amount
rotate_copy copy and rotate a range of elements
这个算法太绝了,应该好好看一下,下面这个方法的理论依据是什么.
void _Rotate(_RI _F, _RI _M, _RI _L, _Pd *, _Ty *)
{_Pd _D = _M - _F;
_Pd _N = _L - _F;
for (_Pd _I = _D; _I != 0; )
{_Pd _J = _N % _I;
_N = _I, _I = _J; }
if (_N < _L - _F)
for (; 0 < _N; --_N)
{_RI _X = _F + _N;
_RI _Y = _X;
_Ty _V = *_X;
_RI _Z = _Y + _D == _L ? _F : _Y + _D;
while (_Z != _X)
{*_Y = *_Z;
_Y = _Z;
_Z = _D < _L - _Z ? _Z + _D
: _F + (_D - (_L - _Z)); }
*_Y = _V; }}
这个方法复杂度是n, 可是我却不能用理论证明这个方法是正确的.
主要思路是这样的,先求出最大公约数,然后从F+N这个位置开始,太奇妙的了.然后就导致整个的轮回.这个地方,真的非常奇怪. 搞不明白,但这方法绝对相当的有效.
rotate_copy();

28,search(), search_n()
这个算法并不是我想像中的是KMP,其实也不可能是KMP的, KMP只适合于字符串类的,其它的不适合,毕竟这是一个通用的了.代码如下.
_FI1 _Search(_FI1 _F1, _FI1 _L1, _FI2 _F2, _FI2 _L2,
_Pd1 *, _Pd2 *)
{_Pd1 _D1 = 0;
_Distance(_F1, _L1, _D1);
_Pd2 _D2 = 0;
_Distance(_F2, _L2, _D2);
for (; _D2 <= _D1; ++_F1, --_D1)
{_FI1 _X1 = _F1;
for (_FI2 _X2 = _F2; ; ++_X1, ++_X2)
if (_X2 == _L2)
return (_F1);
else if (!(*_X1 == *_X2))
break; }
return (_L1); }
虽然效率不高,但是通用性不错的讲.
_FI1 _Search_n(_FI1 _F1, _FI1 _L1,
_Pd2 _N, const _Ty& _V, _Pd1 *)
{_Pd1 _D1 = 0;
_Distance(_F1, _L1, _D1);
for (; _N <= _D1; ++_F1, --_D1)
{_FI1 _X1 = _F1;
for (_Pd2 _D2 = _N; ; ++_X1, --_D2)
if (_D2 == 0)
return (_F1);
else if (!(*_X1 == _V))
break; }
return (_L1); }

29,set_difference()
这个算法要求是必须序排列的,代码如下的.并不是我想像中的那两个树的比较,当然在set class里面,肯定要有实现的,具体是怎么实现,那看的时候,再仔细看一下.
_OI set_difference(_II1 _F1, _II1 _L1, _II2 _F2, _II2 _L2,
_OI _X)
{for (; _F1 != _L1 && _F2 != _L2; )
if (*_F1 < *_F2)
*_X++ = *_F1++;
else if (*_F2 < *_F1)
++_F2;
else
++_F1, ++_F2;
return (copy(_F1, _L1, _X)); }
set_intersection()
_OI set_intersection(_II1 _F1, _II1 _L1, _II2 _F2, _II2 _L2,
_OI _X)
{for (; _F1 != _L1 && _F2 != _L2; )
if (*_F1 < *_F2)
++_F1;
else if (*_F2 < *_F1)
++_F2;
else
*_X++ = *_F1++, ++_F2;
return (_X); }
set_union()
_OI set_union(_II1 _F1, _II1 _L1, _II2 _F2, _II2 _L2, _OI _X)
{for (; _F1 != _L1 && _F2 != _L2; )
if (*_F1 < *_F2)
*_X++ = *_F1++;
else if (*_F2 < *_F1)
*_X++ = *_F2++;
else
*_X++ = *_F1++, ++_F2;
return (copy(_F2, _L2, copy(_F1, _L1, _X))); }
30, sort()
使用的是快排,并且还是递归排序,
  sort_heap() 把一个堆,变成一个有序的队列
  stable_partition()
stable_sort()
swap()
swap_range()
transform()
unique()这个记住了,是去除相邻的重复元素.如果两个元素相同,但不相邻,也不能进入删除.
  unique_copy()
unique_bound();