[算法] - c++笔试中algorithm常用函数(STL)

你有没有被面试官说过:你这个STL了解的不够啊。。有没有看到同样是C++为什么别人的代码还能那么少。。。好吧玄机都在#include里面。官方函数使用方法:http://www.cplusplus.com/reference/algorithm/

考试用#include万能头文件好了

常用功能:交换swap,逆序reverse ,旋转rotate,排序sort,排列组合permutation,查找find,划分(partition)去重set vec(不是alg的),统计count,初始化fill(不是alg的)

目录

再插几条新闻(常错和捡漏)

1. map

2. queue

3. algorithm

4. string

5. 优先级队列、大根堆、小根堆、priority_queue / multiset / multimap

插播两条新闻

1. erase函数 左闭右开:

2. char 变成 int  ('10'-'0')

3. 字符串拼接 9后面跟着n个0 (直接+=)

4. cctype

5. 利用set为vector数组去重(set(vec.begin(), vec.end()))

1. 交换两个元素 swap(arr[1], arr[2]);//直接交换不用&换地址

2. 反转元素的次序 reverse()

全部逆序

部分逆序,实现左移n为字符串的功能

3. rotate/rotate_copy旋转

rotate(vec.begin(),vec.begin()+3,vec.end())前面3个移到后面

rotate_copy(input.first(),input.middle,input.last(),res.first())

4. std::sort(str.begin(),str.end(),cmp);某认从小到大

string内部排序

vector排序,按照字典序(ASCII 码值)排序,不用管长度

自定义排序示例,bool cmp(string qian,string hou);qian,从小到大<>

其他排序方式的实现   (struct中bool operator() (int i,int j))

5. 是否是用一个父产生的排序 is_permutation

6. 按字典序的上/下一个排列 next_permutation(start(),end(),cmp)

部分排列

自定义排列的顺序。

7. 字典序lexicographical_compare

8. 查找find ,find_first_of , find_if , adjacent_find(二分可用)

find(vec.begin(),vec.end(),value); 本身就是查找第一个

find_first_of (r1.begin(),r1.end(),r2.begin(),r2.end()) 在r1中查找第一个r2中的元素

find_if(first,end,pre)   pre是一个bool的判断谓词

adjacent_find 用于查找相等或满足条件的邻近元素对

9. 前后划分partition/stable_partition(如:奇数在前,偶数在后。前后的这种划分)

10. 计数count(a.begin(),a.end(),value)

count_if(a.begin(),a.end(),pre)

11. 容器相等equal (I1 first1, I1 last1, I2 first2, pred);pre可有可无

12. 替换 replace_if (v.begin(), v.end(), IsOdd, 0)

13. 移除 std::remove_if (pbegin, pend, IsOdd);

14. 随机打乱 std::random_shuffle ( v.begin(), v.end() );

15. 构建大根堆

来一道今年前些天华为的真题试试威力(字符串输入合法非法去重左移外排)

 


 

再插几条新闻(常错和捡漏)

1. map

  • mymap.count(key)key的个数
  • map.begin的用法
 for ( auto it = mymap.begin(); it != mymap.end(); ++it )
    std::cout << " " << it->first << ":" << it->second;
  • map.find的用法,而不是find(map.begin()...)

    it = mymap.find('b');
    if (it != mymap.end())
      mymap.erase (it);
  • map::lower_bound(不小于的第一个索引)/upper_bound(这里的map是有序的,自动按照key值排序,所以可以截取的删除)而且删除了开头,结尾闭区间《algorithm中也有,map之所以自带,是因为本身就是有序的,vec没有自带,需要sort之后,然后用algorithm中的》
  mymap['a']=20;mymap['b']=40;mymap['c']=60;
  mymap['d']=80;mymap['e']=100;

  itlow=mymap.lower_bound ('b');  // itlow points to b
  itup=mymap.upper_bound ('d');   // itup points to e (not d!)

  mymap.erase(itlow,itup);        // erases [itlow,itup)

  for (std::map::iterator it=mymap.begin(); it!=mymap.end(); ++it)
    std::cout << it->first << " => " << it->second << '\n';
out:
a => 20
e => 100
  • swap(直接交换两个map)
 std::map foo,bar;

  foo['x']=100;
  foo['y']=200;

  bar['a']=11;
  bar['b']=22;
  bar['c']=33;

  foo.swap(bar);

foo contains:
a => 11
b => 22
c => 33
bar contains:
x => 100
y => 200

2. queue

注意是front,priority_queue中是top。

3. algorithm

  • lower_bound (不小于  大于等于的第一个索引)/ upper_bound大于的第一个索引) 核心是二分做的,要求之前sort
  std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30

  std::vector::iterator low,up;// 索引
  low=std::lower_bound (v.begin(), v.end(), 20); //          ^
  up= std::upper_bound (v.begin(), v.end(), 20); //                   ^

int pos3=lower_bound(num,num+6,7,greater())-num;  //返回数组中第一个小于或等于被查数的值 int pos4=upper_bound(num,num+6,7,greater())-num;  //返回数组中第一个小于被查数的值 
  • binary_search二分查找是否存在,返回bool
  • 求交、求并、求差  set_intersection  set_union set_difference,必须先sort,返回迭代器it配合vec.resize(it-vec.begin)使用
set_intersection (first, first+5, second, second+5, v.begin())
  int first[] = {5,10,15,20,25};
  int second[] = {50,40,30,20,10};
  std::vector v(10);                      // 0  0  0  0  0  0  0  0  0  0
  std::vector::iterator it;

  std::sort (first,first+5);     //  5 10 15 20 25
  std::sort (second,second+5);   // 10 20 30 40 50
  // it只想最后一个交集
  it=std::set_intersection (first, first+5, second, second+5, v.begin());
  // resize(2)变成2个
                                               // 10 20 0  0  0  0  0  0  0  0
  v.resize(it-v.begin());                      // 10 20

4. string

push_back 和 pop_back

if(str.find_first_of('a')==-1)如果没有找到该字符

str.erase(str.begin() + right);

5. 优先级队列、大根堆、小根堆、priority_queue / multiset / multimap

priority_queue 默认从大到小(大根堆)

  std::priority_queue mypq;

  mypq.push(30);
  mypq.push(100);
  mypq.push(25);
  mypq.push(40);

  std::cout << "Popping out elements...";
  while (!mypq.empty())
  {
     std::cout << ' ' << mypq.top();
     mypq.pop();
  }
  std::cout << '\n';

priority_queue vector,greater>小根堆  greater在functional头文件当中

priority_queuevector,cmp> 对链表进行大根堆

struct cmp {// 小根堆~!~~~~~~ 这里是ListNode是结构体,必须这么写
        bool operator()(ListNode* l1, ListNode* l2) {
            return l1->val > l2->val;
        }
    };

priority_queue里面是top不是front了。而且priority_queue中的greater和set中的正相反。

--------------------------------------------------------------------------------------

multiset> greadterSet;  9 9 8 7 7 5 4 1 0 0 
multiset> lessSet; 0 0 1 4 5 7 7 8 9 9  // 这里less是小根堆,优先级队列相反
multiset defaultSet; 0 0 1 4 5 7 7 8 9 9 // 默认小根堆

---------------------------------------------------------------------------------------

使用mutimap代替优先队列,mutimap会自动对key从小到大排序,可以免去编写比较函数的麻

multimap headMap;key从小到大排序 默认

multimapgreater>headMap

 

 

插播两条新闻

1. erase函数 左闭右开

(1)erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符

(2)erase(position);删除position处的一个字符(position是个string类型的迭代器)

(3)erase(first,last);删除从first到last之间的字符(first和last都是迭代器) 左闭右开

// string::erase
#include 
#include 

int main ()
{
  std::string str ("This is an example sentence.");
  std::cout << str << '\n';
                                           // "This is an example sentence."
  str.erase (10,8);                        //            ^^^^^^^^
  std::cout << str << '\n';
                                           // "This is an sentence."
  str.erase (str.begin()+9);               //           ^
  std::cout << str << '\n';
                                           // "This is a sentence."
  str.erase (str.begin()+5, str.end()-9);  //       ^^^^^
  std::cout << str << '\n';
                                           // "This sentence."
  return 0;
}

2. char 变成 int  ('10'-'0')

'10'->10   '10'-'0'

3. 字符串拼接 9后面跟着n个0 (直接+=)

9后面跟着n个0

string a="9";
string b="0"
for(int i =0;i

4. cctype

不常用的勾掉了。右图显示了char的while的使用

[算法] - c++笔试中algorithm常用函数(STL)_第1张图片  [算法] - c++笔试中algorithm常用函数(STL)_第2张图片

 

5. 利用set为vector数组去重(set(vec.begin(), vec.end()))

set st(vec.begin(), vec.end());

vec.assign(st.begin(), st.end());#用其他的模块初始化

vectorvec(st.begin(), st.end());//声明的时候直接初始化,都可以这样

vector vec;
vec = { 1, 2, 3, 4, 8, 9, 3, 2, 1, 0, 4, 8 };
set st(vec.begin(), vec.end());
vec.assign(st.begin(), st.end());#用其他的模块初始化

1. 交换两个元素 swap(arr[1], arr[2]);//直接交换不用&换地址

这个需要注意的是std中也有swap, 当你引入algorithm和std之后,用swap时可以加入std::swap

int arr[1,2,3,4];
swap(arr[1], arr[2]);//直接交换不用&换地址

2. 反转元素的次序 reverse()

  • 全部逆序

string str("hello");
//如何才能只反转ello,即变成holle?如下
reverse(str.begin()+1,str.end());
  • 部分逆序,实现左移n为字符串的功能

如:abcdef,左移2,是cdefab

reverse(str.begin(),str.begin()+2);

reverse(str.begin()+2,str.end());

reverse(str.begin(),str.end());

3. rotate/rotate_copy旋转

其实和上面的用reverse实现的左移的功能是一样的。

rotate(vec.begin(),vec.begin()+3,vec.end())前面3个移到后面

template 
  void rotate (ForwardIterator first, ForwardIterator middle,
               ForwardIterator last)
{
  ForwardIterator next = middle;
  while (first!=next)
  {
    swap (*first++,*next++);
    if (next==last) next=middle;
    else if (first==middle) middle=next;
  }
}
int main () {
  std::vector myvector;

  // set some values:
  for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9

  std::rotate(myvector.begin(),myvector.begin()+3,myvector.end());
                                                  // 4 5 6 7 8 9 1 2 3
  // print out content:
  std::cout << "myvector contains:";
  for (std::vector::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

rotate_copy(input.first(),input.middle,input.last(),res.first()

template 
  OutputIterator rotate_copy (ForwardIterator first, ForwardIterator middle,
                              ForwardIterator last, OutputIterator result)
{
  result=std::copy (middle,last,result);
  return std::copy (first,middle,result);
}
int main () {
  int myints[] = {10,20,30,40,50,60,70};

  std::vector myvector (7);

  std::rotate_copy(myints,myints+3,myints+7,myvector.begin());

  // print out content:
  std::cout << "myvector contains:";
  for (std::vector::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
myvector contains: 40 50 60 70 10 20 30

4. std::sort(str.begin(),str.end(),cmp);某认从小到大

是一种根据实际数据智能选择排序算法的函数,sort()会将区间[beg,end)内的元素排序,默认升序

sort(v.begin(), v.end()); //实现排序,正序排列
bool cmp(int a,int b)
{
    return a>b;//降序排列
}
int array[5]={1,2,3,4,5};
sort(array,array+4,cmp);//通过自定义cmp函数将其改为降序排序

输出为:4 3 2 1 5

  • string内部排序

sort(str.begin(),str.end());

  • vector排序,按照字典序(ASCII 码值)排序,不用管长度

先放到vectorvec当中

然后sort(vec.begin(),vec.end());

  • 自定义排序示例,bool cmp(string qian,string hou);qian

题目大致是:输入若干行由0和1组成的串,将这些串排序输出。

排序规则是:首先按长度排序,长度相同时,按1 的个数多少进行排序,1 的个数相同时再按ASCII 码值排序。

bool cmp(string s1, string s2)
{
    int t1 = count(str1.begin(),str1.end(), '1');
    int t2 = count(str2.begin(),str2.end(), '1');
           
    if(s1.length() !=s2.length()) 
    { 
        return s1.length() 
  • 其他排序方式的实现   (struct中bool operator() (int i,int j))

struct myclass {
  bool operator() (int i,int j) { 
      return (i

5. 是否是用一个父产生的排序 is_permutation

将range [first1,last1]中的元素与以first2开头的元素进行比较,如果两个范围中的所有元素都匹配,即使顺序不同,也会返回true。

std::array bar = {3,1,4,5,2};

std::is_permutatio cegin()) 这两个是相等的。

 

6. 按字典序的上/下一个排列 next_permutation(start(),end(),cmp)

按字典序的下一个排列next_permutation(),按字典序的前一个排列 prev_permutation(),需要先将其sort升序排列好,再用

do//do-while循环和next_permutation、prev_permutation更配喔~
{
    res.push_back(str);
}while(next_permutation(str.begin(),str.end()));
//next_permutation()执行一次 当前的str序列abc 就变成了 升序中的下一个str序列acb
//当 当前的str序列 是 最后一种str序列cba ,那么它就会变成最初的str序列abc
  • 部分排列

while(next_permutation(num,num+3))中的3改为2时,输出就变为了:

  • 自定义排列的顺序。

如修改字典序为:'A'<'a'<'B'<'b'<...<'Z'<'z'.请按照这个依次写出排列的内容。

//我把cmp中char a看成是前一个内容,b是后一个内容,return a

7. 字典序lexicographical_compare

lexicographical_compare(first.begin(),first.end(),last.begin(),last.end(),cmp)默认ascii码从小到大,默认前小,返回true

[算法] - c++笔试中algorithm常用函数(STL)_第3张图片

// lexicographical_compare example
#include      // std::cout, std::boolalpha
#include     // std::lexicographical_compare
#include        // std::tolower

// a case-insensitive comparison function:
bool mycomp (char c1, char c2)
{ return std::tolower(c1)

8. 查找find ,find_first_of , find_if , adjacent_find(二分可用)

  • find(vec.begin(),vec.end(),value); 本身就是查找第一个

vector::itertation iter = find(vec.begin(),vec.end(),value);
if(iter!=vec.end())
//说明存在,iter就是地址,*iter就是value,
//这个是因为,函数设定成这样了,如果find不存在,自动返回vec.end()的地址。

类似地,由于指针的行为与作用在内置数组上的迭代器一样,因此也可以使用find来搜索数组:

int ia[6] = {27 , 210 , 12 , 47 , 109 , 83};
int search_value = 83;
int *result = find(ia , ia + 6 , search_value);
cout<<"The value "<
  • find_first_of (r1.begin(),r1.end(),r2.begin(),r2.end()) 在r1中查找第一个r2中的元素

roster1可以是list对象,而roster2则可以是vector对象、 deque对象或者是其他序列。只要这两个序列的的元素可使用相等(==)操作符进行比较即可。如果roster1是list< string>对象,则roster2可以使vector对象,因为string标准库为string对象与char* 对象定义了相等(==)操作符。

这个算法带有两对迭代器参数来标记两端元素范围:第一段范围内查找与第二段范围中任意元素匹配的元素然后返回一个迭代器,指向第一个匹配的元素。如果找不到匹配元素,则返回第一个范围的end迭代器。

假设roster1和roster2是两个存放名字的list对象,可使用find_first_of统计有多少个名字同时出现在这两个列表中:

size_t cnt = 0;
list::iterator it = roster1.begin();
 
// look in roster1 for any name also in roster2
while((it = find_first_of(it , roster1.end() , roster2.begin() , roster2.end())) != roster1.end())
{
    ++cnt;
    // we got a match , increment it to look in the rest of roster1
    ++it;
}
cout<<"Found "<
  • find_if(first,end,pre)   pre是一个bool的判断谓词

//谓词判断函数 divbyfive : 判断x是否能5整除

bool divbyfive(int x)

{return x % 5 ? 0 : 1;}
  • adjacent_find 用于查找相等或满足条件的邻近元素对

参考自:https://blog.csdn.net/hyg0811/article/details/10390591

bool myfunction (int i, int j) {
  return (i==j);//前一个等于后一个
}

int main () {
  int myints[] = {5,20,5,30,30,20,10,10,20};
  std::vector myvector (myints,myints+8);
  std::vector::iterator it;

  // using default comparison:
  it = std::adjacent_find (myvector.begin(), myvector.end());

  if (it!=myvector.end())
    std::cout << "the first pair of repeated elements are: " << *it << '\n';

  //using predicate comparison:
  it = std::adjacent_find (++it, myvector.end(), myfunction);

  if (it!=myvector.end())
    std::cout << "the second pair of repeated elements are: " << *it << '\n';

  return 0;
}

Output:
the first pair of repeated elements are: 30
the second pair of repeated elements are: 10
 

9. 前后划分partition/stable_partition(如:奇数在前,偶数在后。前后的这种划分)

  • partition是会打乱原先的顺序,stable_partition则不会
  • 和std:: partition不同的是,stable_partition是稳定的,保持原有元素的相对顺序。 

双向迭代器 BidirectionalIterator stable_partition (BidirectionalIterator first, BidirectionalIterator last, UnaryPredicate pred)

返回值:指向第二组(哪些使pred返回false)第一个元素的迭代器,或者第二组为空,返回last

如:奇数在前,偶数在后,传统的方法,是定义前后指针,前面的指针如果指向的值是奇数就遍历,偶数就不动(while),后指针,如果指向的是偶数就遍历,奇数就不动,然后再前后交换,使得奇数在前,偶数在后,但是会发生位置的相对变化。利用partition的方法。

bool IsOdd (int i) { return (i%2)==1; }

int main () {
  std::vector myvector;

  // set some values:
  for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9

  std::vector::iterator bound;
  bound = std::stable_partition (myvector.begin(), myvector.end(), IsOdd);

  // print out content:
  std::cout << "odd elements:";
  for (std::vector::iterator it=myvector.begin(); it!=bound; ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "even elements:";
  for (std::vector::iterator it=bound; it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
odd elements: 1 3 5 7 9
even elements: 2 4 6 8

10. 计数count(a.begin(),a.end(),value)

  • count_if(a.begin(),a.end(),pre)

       bool IsOdd (int i) { return ((i%2)==1); }

11. 容器相等equal (I1 first1, I1 last1, I2 first2, pred);pre可有可无

// equal algorithm example
#include      // std::cout
#include     // std::equal
#include        // std::vector

bool mypredicate (int i, int j) {
  return (i==j);
}

int main () {
  int myints[] = {20,40,60,80,100};               //   myints: 20 40 60 80 100
  std::vectormyvector (myints,myints+5);     // myvector: 20 40 60 80 100

  // using default comparison:
  if ( std::equal (myvector.begin(), myvector.end(), myints) )
    std::cout << "The contents of both sequences are equal.\n";
  else
    std::cout << "The contents of both sequences differ.\n";

  myvector[3]=81;                                 // myvector: 20 40 60 81 100

  // using predicate comparison:
  if ( std::equal (myvector.begin(), myvector.end(), myints, mypredicate) )
    std::cout << "The contents of both sequences are equal.\n";
  else
    std::cout << "The contents of both sequences differ.\n";

  return 0;
}

12. 替换 replace_if (v.begin(), v.end(), IsOdd, 0);

 

13. 移除 std::remove_if (pbegin, pend, IsOdd);

 

14. 随机打乱 std::random_shuffle ( v.begin(), v.end() );

15. 构建大根堆

一是在找k个小的树的时候
第一种直接构建相关变量
第二种利用push_heap,pop_heap的操作,将一个vector弄成大根堆。
形式一:
typedef  multiset> intSet;#直接定义个大根堆
typedef multiset>::iterator intSetIter;
intSet& leastNumbers,如果leastNumbers >            intSet;
typedef multiset >::iterator  setIterator;
​
void GetLeastNumbers_Solution2(const vector& data, intSet& leastNumbers, int k)
{
    leastNumbers.clear();
    if(k < 1 || data.size() < k)
        return;
    vector::const_iterator iter = data.begin();
    for(; iter != data.end(); ++ iter)
    {
        if((leastNumbers.size()) < k)
            leastNumbers.insert(*iter);
        else
        {
            setIterator iterGreatest = leastNumbers.begin();
            if(*iter < *(leastNumbers.begin()))
            {
                leastNumbers.erase(iterGreatest);
                leastNumbers.insert(*iter);
            }
        }
    }
}
​
​
​
形式二:
利用函数和vector弄
先定义私有成员变量 vector max;
利用push_heap pop_heap的方式结合vector.pop_back()的方法
max.push_back(num);
push_heap(max.begin(), max.end(), less());
num = max[0];##记录堆顶
pop_heap(max.begin(), max.end(), less());##堆顶和最后的互换
max.pop_back();##弹出最后一个      上两个结合heapify
min.push_back(num);
push_heap(min.begin(), min.end(), greater());
template class DynamicArray
{
public:
    void Insert(T num)
    {
        if(((min.size() + max.size()) & 1) == 0)
        {
            if(max.size() > 0 && num < max[0])
            {
                max.push_back(num);
                push_heap(max.begin(), max.end(), less());
​
                num = max[0];
​
                pop_heap(max.begin(), max.end(), less());
                max.pop_back();
            }
​
            min.push_back(num);
            push_heap(min.begin(), min.end(), greater());
        }
        else
        {
            if(min.size() > 0 && min[0] < num)
            {
                min.push_back(num);
                push_heap(min.begin(), min.end(), greater());
​
                num = min[0];
​
                pop_heap(min.begin(), min.end(), greater());
                min.pop_back();
            }
​
            max.push_back(num);
            push_heap(max.begin(), max.end(), less());
        }
    }
​
    T GetMedian()
    {
        int size = min.size() + max.size();
        if(size == 0)
            throw exception("No numbers are available");
​
        T median = 0;
        if((size & 1) == 1)
            median = min[0];
        else
            median = (min[0] + max[0]) / 2;
​
        return median;
    }
​
private:
    vector min;
    vector max;
};
​

来一道今年前些天华为的真题试试威力(字符串输入合法非法去重左移外排)

图片摘自网络

[算法] - c++笔试中algorithm常用函数(STL)_第4张图片

[算法] - c++笔试中algorithm常用函数(STL)_第5张图片

#include 
#include 
#include 
#include 
#include 
#include
using namespace std;

int main() {
	vectorvalid_vec;//有效的字符串
	vectorinvalid_vec;//无效字符串
	char input[100];
	do{// 判断是否 输入结束了
		cin.getline(input, 100);
		bool valid = true;
		int i = 0;
		do{//判断字符串是否结束了
			charc = input[i];
			if (!isalnum(c)) {
				valid = false;
				break;
			}
			i++;
		} while (input[i] != '\0');//判断字符串是否结束了
		if (!valid)
			invalid_vec.push_back(input);
		else
			valid_vec.push_back(input);
	} while (input[0] != '\0');//判断输入是否是空行,如果是,就结束了
	// 去重valid_vec存储去重后的
	
	setst(valid_vec.begin(), valid_vec.end());
	valid_vec.assign(st.begin(), st.end());
	
	//输出去重后的合法字符串
	int nums_valid = valid_vec.size();
	for (int i = 0; i < nums_valid-1; i++)
	{
		cout << valid_vec[i] << " ";
	}
	cout << valid_vec[nums_valid - 1]<

 

你可能感兴趣的:(算法,数据结构,CV面经,CV面经+算法总结)