前言
自CSDN开展编程竞赛以来,每次都参加。在比赛中,收获了很多,也有很多感悟。虽然工作了很多年,代码也写了很多,但基本就是调用开源的API,像算法这种高逻辑的代码编写其实很少。个人对编程语言的认知还停留在10年前。这几次参赛都是用C语言,在比赛中越来越感觉到C语言的不便跟不足。
为什么选择C++
一个语言是否成熟看它是否有丰富的类库。
人工智能,自动运维一般都是用Python,因为有现成的包可以调用。例如要对一个数组进行排序,通过系统自带的排序函数就可以很快的完成,像Java,C++等都有自带的排序函数。如果用C语言,就要自己去实现了,无疑就会额外耗费很多时间,在这分秒必争的比赛中,就会落后于其他人。虽然你并不弱,但是别人有更好的工具,效率比你高,这就是现实。
算法比赛一般用的都是Java,学习Java的人毕竟比较多,并且包含的包也多,可以用的函数也多。但本人是从C/C++走过来到,所以对C++比较容易接受些。对C++的认识还停留在面向对象编程,但在算法比赛中,主要是用C++的容器,以及一些内置函数。随着C/C++11,C/C++14乃至C/C++20标准的到来,更好的特性,更方便的写法。
vector的遍历
C++的一大特点就是有很多容器,比起自己写链表要方便很多。算法比赛中基本用的都是vector容器。已经有很多新写法,我们先看一下。
插入一个元素
通常我们使用push_back来插入一个元素,现在还可以使用emplace_back来插入一个元素,如果容器里存的是类,初始化效率就相差很大,emplace_back比push_back少一次拷贝,详细可百度。
vector<int> vec;
vec.push_back(1);
vec.emplace_back(4);
......
常规的遍历方式
通过数组大小及下标遍历
for(int i=0;i<vec.size();i++){
cout<<vec[i]<<" ";
}
cout<<endl;
通过iterator指针遍历
vector<int>::iterator it=vec.begin();
while(it!=vec.end()){
cout<<*it<<" ";
it++;
}
cout<<endl;
新型的遍历方式
对有的人来说可能并不新鲜,但对停留在10年前的认知的我来说算是比较新的。
auto指针方式
auto itauto=vec.begin();
while(itauto!=vec.end()){
cout<<*itauto<<" ";
itauto++;
}
cout<<endl;
还有for循环方式,data的数据类型就是int,有点象php里面的foreach
for(auto data:vec){
cout<<data<<" ";
}
cout<<endl;
倒序遍历
之前一直以为只能用it++,不能用it–,手动试了下是可行的,指向最后,然后遍历到前面
auto ptr=vec.end();
while(ptr!=vec.begin()){
ptr--;
cout<<*ptr<<" ";
}
cout<<endl;
比较正规的倒序遍历,使用rbegin和rend函数
auto ptr2=vec.rbegin();
while(ptr2!=vec.rend()){
cout<<*ptr2<<" ";
ptr2++;
}
cout<<endl;
排序函数sort的使用
C++中有sort函数,需要包含头文件#include<algorithm>
sort的简单实用
对一个整数数组进行排序
int a[5] = {1,5,9,7,3};
sort(a, a + 5);
sort(b, b + 5,greater<int>());//大的在前
对容器进行排序,int,string都可以
vector<int> arr = {1,5,9,7,3};
sort(arr.begin(), arr.end());
vector<string> verstr={"blue","red","green","black","white"};
sort(verstr.begin(),verstr.end());
输出结果
1 3 5 7 9
black blue green red white
sort自定义函数使用
通过自定义函数可以实现自己对排序规则的一些判断
例如根据到0点的距离从小到大进行排序
bool comint(int a,int b){
return abs(a)<abs(b);
}
......
int c[5] = {-1,2,-3,4,-5};
sort(c, c + 5,comint);
for (int i = 0; i < 5; i++) {
cout<<c[i]<<' ';
}
cout << endl;
输出结果
-1 2 -3 4 -5
碰到char字符串的排序,需要自定义比较函数,比用C要方便多了。
bool comstr(const char* a,const char* b){
return strcmp(a,b)<0;
}
......
const char * str[5]={"blue","red","green","black","white"};
sort(str,str+5,comstr);
for (int i = 0; i < 5; i++) {
cout<<str[i]<<' ';
}
cout << endl;
输出结果
black blue green red white
求和/拼接函数accumulate的使用
用中文怎么描述还不怎么清楚,如果是整形就是求和,如果是字符串就是拼接,类型要支持+运算符,不行就用自定义
注意要包含头文件#include<numeric>
accumulate简单使用
注意第三个参数为初始化类
vector<int> vecint={1,2,3,4,5};
vector<string> verstr={"ab","cd","ef","gh"};
int retint = accumulate(vecint.begin(),vecint.end(),0);
string retstr = accumulate(verstr.begin(),verstr.end(),string(""));
string retstrx = accumulate(verstr.rbegin(),verstr.rend(),string(""));
cout<<"retint:"<<retint<<endl;
cout<<"retstr:"<<retstr<<endl;
cout<<"retstrx:"<<retstrx<<endl;
输出结果
retint:15
retstr:abcdefgh
retstrx:ghefcdab
accumulate自定义使用
同自定义函数可以实现其他功能
例如通过及格人数,字符串通过特定字符拼接(编程大赛第四届单词逆序)
//统计及格人数
int funcint(int result,int data){
if(data>=60){
result++;
}
return result;
}
//字符串用空格分隔
string funcstring(string result,string data){
if(!result.empty()){
result+=" ";
}
result+=data;
return result;
}
......
vector<int> vecint2={60,70,55,45,80};
vector<string> verstr2={"I","am","a","boy!"};
int retint2 = accumulate(vecint2.begin(),vecint2.end(),0,funcint);
string retstr2 = accumulate(verstr2.rbegin(),verstr2.rend(),string(""),funcstring);
cout<<"retint2:"<<retint2<<endl;
cout<<"retstr2:"<<retstr2<<endl;
输出结果
retint2:3
retstr2:boy! a am I
总结
C++确实有很多方便的函数,做起题来就方便不少。例如最后一个例子,可以解决编程大赛第四届单词逆序这道题,通过将读取的单词一个一个的放入容器,再通过逆序函数,自定义间隔符就行了。用C语言也可以做这道题,简单点就是从末尾查找空格,从后往前输出,如果自己用链表那耗时就更长了,相比之下,用C++是比较简洁,快速的。如果是统计单词是否重复出现,用C语言就没C++那么方便了。