C++STL标准库学习笔记(十四)算法(下)

前言:

  在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来。

  在这一篇文章中,我们主要对STL中的算法进行简单的介绍,这篇文章接着上一篇文章(https://www.cnblogs.com/AwakeFantasy/p/15859234.html)。

正文:

2.3. 删除算法

  删除容器中的某些元素

  删除--不会使容器中的元素减少

    将所有应该被删除的元素看作空位置

    用留下的元素从后往前移,依次去填空位置

    元素前移后,它原来的位置也就算是空位置

    也应由后面的留下的元素来填上

    最后,没有被填上的空位置,维持其原来的值不变

  删除算法不应作用于关联容器

  remove:删除区间中等于某个值的元素

  remove_if:删除区间中满足某种条件的元素

  remove_copy:拷贝区间到另一个区间,等于某个值的元素不拷贝

  remove_copy_if:拷贝区间到另一个区间,符合某种条件的元素不拷贝

  unique:删除区间中连续相等的元素,只留下一个(可自定义比较器),unique返回最后一个元素后面的迭代器,用它减begin就可以知道长度

  unique_copy:拷贝区间到另一个区间,连续相等的元素,只拷贝第一个到目标区间()

  算法复杂度都是O(n)

 

unique

  template<class Fwdit>

  Fwdit unique(Fwdit first, Fwdit last);

    用==判断是否相等

  templast<class Fwdit, class Pred>

  Fwdit unique(Fwdit first, Fwdit last, Pred pr);

    用pr(x,y)为true说明x和y相等

    对[first, last)这个序列中连续相等的元素,只留下第一个

    返回值是迭代器,指向元素删除后的区间的最后一个元素的后面

  样例:(remove的)

复制代码
 1 #include<iostream>
 2 #include<vector>
 3 #include<iterator>
 4 #include<algorithm>
 5 using namespace std;
 6 int main(int argc, char const *argv[])
 7 {
 8     int a[5] = {1,2,3,2,5};
 9     int b[6] = {1,2,3,2,5,6};
10     ostream_iterator<int> oit(cout,",");
11     int* p = remove(a,a+5,2);
12     cout<<"1)";
13     copy(a,a+5,oit);
14     cout<<endl;//输出:1)1,3,5,2,5,//这里就能看出前面说的删除移位了
15     cout<<"2)"<<p-a<<endl;//输出:2)3
16     vector<int> v(b,b+6);
17     remove(v.begin(),v.end(),2);
18     cout<<"3)";
19     copy(v.begin(),v.end(),oit);
20     cout<<endl;//输出:3)1,3,5,6,5,6,
21     cout<<"4)";
22     cout<<v.size()<<endl;//输出:4)6
23     return 0;
24 }
复制代码

  样例中删除了a中的两个“2”,结果导致3前移了一位,而5补上了3原来的位置,而另一次删除的时候,vector的大小是没动的。

2.4. 变序算法

  变序算法改变容器中的元素的顺序

  但是不改变元素的值

  变序算法不适用于关联容器

  算法复杂度都是O(n)的

  reverse:颠倒区间的前后次序

  reverse_copy:把一个区间颠倒后的结果拷贝到另一个区间,源区间不变

  rotate:将区间进行循环后移

  rotate_copy:将区间以首尾相接的形式进行旋转后的结果拷贝到另一个区间,源区间不变。

  next_permutation:将区间改为下一个排列(可自定义比较器)(如123,132,213之类,这是排列,而它们之间有大小关系,这就是上一个(前面小)下一个(前面大)了)

  prev_permutation:将区间改为上一个排列(可自定义比较器)

  random_shuffle:随机打乱区间内元素的顺序

  partition:把区间内满足某个条件的元素移到前面,不满足该条件的移到后面

stable_patition

  把区间内满足某个条件的元素移到前面

  不满足该条件的移到后面

  而对这两部分元素,分别保持它们原来的先后次序不变

random_shuffle

  template<class Ranit>

  void random_shuffle(Ranit first, Ranit last);

  随机打乱[first, last)中的元素,适用于能随机访问的容器

reverse

  template<class Bidlt>

  void reverse(Bidlt first, Bidlt last);

  颠倒[first,last)顺序

next_permutation

  template<class init>

  bool next_permutaion(init first, init last);

  求下一个排列

  样例:(next_permutation)

复制代码
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<string>
 4 using namespace std;
 5 int main(int argc, char const *argv[])
 6 {
 7     string str = "231";
 8     char szStr[] = "324";
 9     while (next_permutation(str.begin(),str.end()))
10     {
11         cout<<str<<endl;
12     }
13     cout<<"****"<<endl;
14     while (next_permutation(szStr,szStr+3))
15     {
16         cout<<szStr<<endl;
17     }
18     sort(str.begin(),str.end());
19     cout<<"****"<<endl;
20     while (next_permutation(str.begin(),str.end()))
21     {
22         cout<<str<<endl;
23     }
24     
25     return 0;
26 }
27 /*
28 输出;
29 312
30 321
31 ****
32 342
33 423
34 432
35 ****
36 132
37 213
38 231
39 312
40 321
41 */
复制代码

  样例2:(也是这个函数的)

复制代码
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<string>
 4 #include<list>
 5 #include<iterator>
 6 using namespace std;
 7 int main(int argc, char const *argv[])
 8 {
 9     int a[] = {8,7,10};
10     list<int> ls(a,a+3);
11     while (next_permutation(ls.begin(),ls.end()))
12     {
13         list<int>::iterator i;
14         for ( i = ls.begin(); i != ls.end(); i++)
15         {
16             cout<<*i<<" ";
17         }
18         cout<<endl;
19     }
20     
21     return 0;
22 }
复制代码

 

2.5. 排序算法

  比前面的变序算法复杂度更高,一般是O(nlog(n))

  排序算法需要随机访问迭代器的支持

  不适用于关联容器和list

  sort:将区间从小到大排序(可自定义比较器)

  stable_sort:将区间从小到大排序,并保持相等元素之间的相对次序(可自定义比较器)

  partial_sort:对区间部分排序,直到最小的n个元素就位(可自定义比较器)

  partial_sort_copy:将区间前n个元素的排序结果拷贝到别处,源区间不变(可自定义比较器)

  nth_element:对区间部分排序,使得第n小的元素(n从0开始算)就位,而且比它小的都在它前面,比它大的都在它后面(可自定义比较器)

  make_heap:使区间成为一个“堆”(可自定义比较器)

  push_heap:将元素加入一个“堆”区间(可自定义比较器)

  pop_heap:从“堆”区间删除堆顶元素(可自定义比较器)

  sort_heap:将一个“堆”区间进行排序,排序结束后,该区间就是普通的有序区间,不再是“堆”了(可自定义比较器)

sort快速排序

  template<class Ranlt>

  void sort(Ranlt first, Ranlt last)

    按升序排序

    判断x是否应比y靠前,就看x<y是否为true

  template<class Ranlt, class Pred>

  void sort(Ranlt first, Ranlt last, Pred pr);

    按升序排序

    判断x是否应比y靠前,就看pr(x,y)是否为true

  (这些前面的笔记也是有讲过用法的)

  样例:

复制代码
 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 class Myless
 5 {
 6 public:
 7     bool operator()(int n1,int n2)
 8     {
 9         return(n1 % 10)<(n2 % 10);
10     }
11 };
12 
13 int main(int argc, char const *argv[])
14 {
15     int a[] = {14,2,9,111,78};
16     sort(a,a+5,Myless());
17     int i;
18     for ( i = 0; i < 5; i++)
19     {
20         cout<<a[i]<<" ";
21     }
22     cout<<endl;//输出:111 2 14 78 9 
23     sort(a,a+5,greater<int>());
24     for ( i = 0; i < 5; i++)
25     {
26         cout<<a[i]<<" ";
27     }
28     //输出:111 78 14 9 2
29     return 0;
30 }
复制代码

  sort实际上是快速排序,时间复杂度O(n*log(n))

    平均性能最优

    但是最坏的情况下,性能可能非常差

  如果要保证“最坏情况下”的性能,那么可以使用

  stable_sort

  stable_sort实际上是归并排序,特点是能保持相等元素之间的先后次序

  在有足够存储空间的情况下,复杂度为n*log(n),否则复杂度为n*log(n)*log(n)

  stable_sort用法和sort相同

  排序算法要求随机存取迭代器的支持,所以list不能使用排序算法,要使用list::sort

2.6. 有序区间算法

  要求所操作的区间是已经从小到大排好序的

  要求随机访问迭代器的支持

  有序区间算法不能用于关联容器和list

  binary_search:判断区间中是否包含某个元素

  includes:判断是否一个区间中的每个元素,都在另一个区间中

  lower_bound:查找最后一个不小于某值的元素的位置

  upper_bound:查找第一个大于某值的元素的位置

  equal_range:同时获取lower_bound和upper_bound

  merge:合并两个有序区间到第三个区间

  (这些东西在我的之前的笔记中有提到过,红色字体的部分都是Olog(n)的,include要看区间大小,mergeO(n))

  set_union:将两个有序区间的并拷贝到第三个区间

  set_intersection:将两个有序区间的交拷贝到第三个区间

  set_difference:将两个有序区间的差拷贝到第三个区间

  set_symmetric_difference:将两个有序区间的对称差拷贝到第三个区间

  inplace_merge:将两个连续的有序区间原地合并为一个有序区间(就合并嘛)

binary_search

  折半查找

  要求容器已经有序且支持随机访问迭代器,返回是否找到

  template<class Fwdlt, class T>

  bool binary_search(Fwdlt first, Fwdlt last, const T& val);

    上面这个版本,比较两个元素x,y大小时,看x<y

  template<class Fwdlt, class T, class Pred>

  bool binary_search(Fwdlt first, Fwdlt last, const T& val, Pred pr);

    上面这个版本,比较两个元素x,y大小时,若pr(x,y)为true,则认为x小于y

lower_bound

  template<class Fwdlt, class T>

  Fwdlt lower_bound(Fwdlt first, Fwdlt last, const T& val);

    要求[first,last)是有序的

    查找[first,last) 中的,最大的位置Fwdlt,使得[first,Fwdlt)中所有的元素都比val小

equal_range

  template<class Fwdlt, class T>

  pair<Fwdlt, Fwdlt> equal_range(Fwdlt first, Fwdlt last, const T& val);

    要求[first,last)是有序的,

    返回值是一个pair,假设为p,则:

      [first,p.first)中的元素都比val小

      [p.second,last)中的所有元素都比val大

      p.first就是lower_bound的结果

      p.last就是upper_bound的结果

(照我看就只有最后两句有用哈哈哈,毕竟最后两句浅显易懂)

merge

  template<class lnlt1, class lnlt2, class Outlt>

  Outlt merge(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2,Outlt x);

    用<作比较器

 

  template<class lnlt1, class lnlt2, class Outlt, class Pred>

  Outlt merge(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x, Pred pr);

    用pr作比较器

把[first1,last1),[first2,last2)两个升序序列合并,形成第三个升序序列,第三个升序序列以x开头

includes

  template<class lnlt1, class lnlt2>

  bool includes(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2);

 

  template<class lnlt1, class lnlt2, class Pred>

  bool includes(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Pred pr);

  判断[first2,last2)中的每个元素,是否都在[first1, last1)中

    第一个用<作比较器

    第二个用pr作比较器,pr(x,y)==true说明x,y相等

set_difference

  template<class lnlt1, class lnlt2, class Outlt>

  Outlt set_difference(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x);

 

  template<class lnlt1, class lnlt2, class Outlt, class Pred>

  Outlt set_difference(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x, Pred pr);

  (这些模板敲得挺累,其实就是为了说明它们应该传入什么参数)

  求出[first1,last1)中,不在[first2,last2)中的元素,放到从x开始的地方

  如果[first1,last1)里有多个相等元素不在[first2,last2)中,则这多个元素也都会被放入x代表的目标区间里

set_intersection

  template<class lnlt1, class lnlt2, class Outlt>

  Outlt set_intersection(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x);

 

  template<class lnlt1, class lnlt2, class Outlt, class Pred>

  Outlt set_intersection(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x, Pred pr);

  求出[first1,last1),[first2,last2)中共有的元素,放到从x开始的地方

  如果某个元素e在[first1,last1)里出现n1次,在[first2,last2)中出现n2次,则该元素在目标区间里出现min(n1,n2)次

set_symmetric_difference

  template<class lnlt1, class lnlt2, class Outlt>

  Outlt set_symmetric_difference(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x);

 

  template<class lnlt1, class lnlt2, class Outlt, class Pred>

  Outlt set_symmetric_difference(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x, Pred pr);

  把两个区间相互不在另一区间里的元素放入x开始的地方

set_union

  template<class lnlt1, class lnlt2, class Outlt>

  Outlt set_union(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2,Outlt x);

  用<比较大小

 

  template<class lnlt1, class lnlt2, class Outlt, class Pred>

  Outlt set_union(lnlt1 first1, lnlt1 last1, lnlt2 first2, lnlt2 last2, Outlt x, Pred pr);

  用pr比较大小

    求两个区间的并,放到x开始的位置

    如果某个元素e在[first1,last1)里出现n1次,在[first2,last2)中出现n2次,则该元素在目标区间里出现max(n1,n2)次

 

无法分类的东东:

bitset

  template<size_t N>

  class bitset

  {

  .......

  }

  实际使用的时候,N是一个常型整数

  如:

  bit<40>bst;

  bst是一个由40位组成的对象

  用bitset的函数可以方便地访问任何一位

  bitset的成员函数:

  bitset<N>&operator&=(const bitset<N>& rhs);

  bitset<N>&operator|=(const bitset<N>& rhs);

  bitset<N>&operator^=(const bitset<N>& rhs);

  bitset<N>&operator<<=(size_t num);

  bitset<N>&operator>>=(size_t num);

  (位运算)

  bitset<N>&set();//全部设成1

  bitset<N>&set(size_t pos, bool val = true);//设置某位

  bitset<N>&reset();//全部设成0

  bitset<N>&set(size_t pos);//设置某位为0

  bitset<N>&flip();//全部翻转

  bitset<N>&flip(size_t pos);//翻转某位

  reference operator[](size_t pos);//返回对某位的引用

  bool operator[](size_t pos)const;//判断某位是否为1

  reference at(size_t pos);

  bool at(size_t pos)const;

  unsigned long to_ulong()const;//转换成整数

  string to_string()const;//转换成字符串

  size_t count()const;//计算1的个数

  size_t size()const;

  bool operator==(const bitset<N>& rhs)const;

  bool operator!=(const bitset<N>& rhs)const;(判断两个是否不等)

  bool test(size_t pos)const;//测试某位是否为1

  bool any()const;//是否有某位为1

  bool none()const;//是否全部为0

  bitset<N> operator<<(size_t pos)const;

  bitset<N> operator>>(size_t pos)const;

  bitset<N> operator~()const;

  static const size_t bitset_size = N;

  注意:第0位在最右边

后记:

  long long说的就是这两集,实在太长了啊啊啊啊,不过也好,整理出来了完整的笔记,最近过年摸鱼也没少摸,从老家回来后就要回归高效率的生活了,希望新的一年里能做到最好吧。

posted @   AwakeFantasy  阅读(94)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示