cin>>a cout<<a<<endl;
1.首先C++引入库的通用写法
#include <bits/stdc++.h>
using namespace std;
int main(){
return 0;
}
相当于:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
2.结构体
C++的结构体可以包含函数,这样,C++的结构体也具有类的功能,与class不同的是,结构体包含的函数默认为public,而不是private。
struct tag
{
member-list
}variable-list;
注:struct为结构体关键字;
tag为结构体的标志;
member-list为结构体成员变量及成员函数列表,其必须列出其所有成员;
variable-list为此结构体声明的变量;
//带有指针般的结构体
struct dong{
string name;
int m;
int v;
dong *next;
};
dong a={"A",2,6,NULL};
//实现定一个ff[1500]的结构体数组
struct qwe
{
int p,q,v;
}ff[1500];
//带有函数的结构体
struct SAMPLE
{
int x;
int y;
int add() {return x+y;}
}s1;
注意结构体分配空间的特殊性哦
3.声明函数
int GCD(int a,int b)
{
if(b==0)
return a;
else
return GCD(b,a%b);
}
4.构造函数的初始化列表
#include <iostream>
using namespace std;
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
Student(char *name, int age, float score);
void show();
};
//采用初始化列表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
//TODO:
}
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
int main(){
Student stu("小明", 15, 92.5f);
stu.show();
Student *pstu = new Student("李华", 16, 96);
pstu -> show();
return 0;
}
/*
小明的年龄是15,成绩是92.5
李华的年龄是16,成绩是96
*/
如本例所示,定义构造函数时并没有在函数体中对成员变量一一赋值,其函数体为空(当然也可以有其他语句),而是在函数首部与函数体之间添加了一个冒号:,后面紧跟m_name(name), m_age(age), m_score(score)
语句,这个语句的意思相当于函数体内部的m_name = name; m_age = age; m_score = score
;语句,也是赋值的意思。
使用构造函数初始化列表并没有效率上的优势,仅仅是书写方便,尤其是成员变量较多时,这种写法非常简单明了。
初始化列表可以用于全部成员变量,也可以只用于部分成员变量。
前面警示一下自己,下面复习STL中的容器
序列容器
①vector
vector是一个封装动态大小数组的序列容器
#include <bits/stdc++.h>
/*
1.需要引入 #include <vector>
2、Vector作为函数的参数或者返回值时,需要注意它的写法:
double Distance(vector<int>&a, vector<int>&b) 其中的“&”绝对不能少!!!
(1)使用迭代器访问元素.
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;
(2)插入元素: vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
(3)删除元素: vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
(4) 使用reverse将元素翻转:需要头文件#include<algorithm>
reverse(vec.begin(),vec.end());将元素翻转,即逆序排列!
vector <vector <int> > array2(3);
array2[1][2]=9;
保证你的程序会segement failed,原因就是你没有指定向量的大小。
用push_back函数可以解决问题:array2[1].push_back(9);但是好象不太爽。就不能用operator[]吗?答案是肯定的。不过要多加几个步骤,
如下:
for(int i=0;i <3;i++)
array2[i].resize(3);
这样,你就定义了一个3X3的数组了(另一个3在 申明时定义的)。而且你可以随时改变它的大小。
*/
using namespace std;
vector<int>test;//建立一个vector一维int数组
vector<int>test2(10,7);//建立一个vector1维初始大小10,每个元素为7的int数组
int main()
{
vector<vector<int> > p(10);//这个10 不能少
for(int i=0;i<9;i++)//这个也不能少
p[i].resize(9);//resize 定义每一行的大小
vector<int> pp(10,8);//1维
cout<<pp[1]<<endl;//8
cout<<p[1][1]<<endl;// 输出0 没有p[i].resize(9);这个会报错
vector<int> mp[10];//这样可以当2维
// for(int i=0;i<9;i++)
// mp[i].resize(9);
mp[1].push_back(10);//经常这么用的
cout<<mp[1].size()<<endl; //1
cout<<mp[1][0]<<endl;//10
}
②list
list是双向链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。
list 的特点:
(1) 不使用连续的内存空间这样可以随意地进行动态操作;
(2) 可以在内部任何位置快速地插入或删除,当然也可以在两端进行push 和pop 。
(3) 不能进行内部的随机访问,即不支持[ ] 操作符和vector.at() ;
(4) 相对于verctor 占用更多的内存。
#include <bits/stdc++.h>
using namespace std;
int comp(int a){
if(a==8)
return 1;
else
return 0;
}
int main(){
list<int> c0;//空链表
list<int> c1(5);//含5个默认值是0的链表
list<int> c2(5,2);//含5个默认值是2的链表
list<int> c3(c2);//建一个c2的copy链表
list<int> c4(c1.begin(),c1.end());//含c1一个区域元素的链表
list<int>::iterator it;
//在尾部插入
c0.push_back(5);
c0.push_back(4);
c0.push_back(7);
c0.push_back(0);
c0.push_back(8);
//插入insert() 函数的第一个参数是用来指定插入位置的迭代器,第二个参数是被插入元素的个数
it=c0.begin();//不能写成 c0.begin()+1
it++;
c0.insert(it,3);
//返回第一个
cout<<c0.front()<<endl;
//返回最后一个
cout<<c0.back()<<endl;
//list实际元素的个数
cout<<c0.size()<<endl;
//删除第一个元素 注意删除之后it指代的元素
it=c0.begin();
c0.erase(it);
//所有容器做erase操作时都有可能使迭代器失效。改正的原理是使当前迭代器失效时能指向下一个位置
cout<<*it<<endl; //输出删除的那个5
//遍历
for(it=c0.begin();it!=c0.end();it++){
cout<<*it<<" ";
}
cout<<endl;
//默认升序排列
c0.sort();
//遍历
for(it=c0.begin();it!=c0.end();it++){
cout<<*it<<" ";
}
cout<<endl;
//删除第一个元素
c0.pop_front();
//删除最后一个元素
c0.pop_back();
//删除链表中匹配的元素
c0.remove(0);
//删除满足条件的元素 参数为自定义的回调
c0.remove_if(comp);
//遍历
for(it=c0.begin();it!=c0.end();it++){
cout<<*it<<" ";
}
}
关联容器
①set
set这种容器里面存放元素唯一的,不可能有俩个重复的在里面,而且插入的元素是按从小到大排列
#include <iostream>
#include <set> //set这种容器里面存放元素唯一的,不可能有俩个重复的在里面,而且插入的元素是按从小到大排列
using namespace std;
int main()
{
set<int> st;
set<int>::iterator it;
st.insert(2);
st.insert(1);
st.insert(3);
st.insert(8);
printf("%d\n",st.size());
bool isempty=st.empty();//是否为空
int has1=st.count(1);//1这个元素是否在set里面 has1 要不为1 要不为0
int has2=st.count(9);
printf("%d %d\n",has1,has2);
st.erase(1);//撤出1 这个元素
////lower_bound()--返回指向大于(或等于)某值的第一个元素的迭代器
cout<<*st.lower_bound(1)<<endl;//返回set第一个大于等于1的数
cout<<*st.upper_bound(1)<<endl;//返回set第一个大于1的数
//遍历
it=st.begin();
for(it;it!=st.end();it++){
cout<<*it<<" ";
}
//返回与特定键匹配的元素数
cout<<endl<<st.count(2)<<endl;
//返回与特定键匹配的元素数位置
st.clear();
}
②map
Map中的元素是自动按key升序排序,所以不能对map用sort函数
/*、map的说明
1 头文件
#include <map>
2 定义
map<string, int> my_Map;
或者是typedef map<string, int> MY_MAP;
MY_MAP my_Map; */
#include <bits/stdc++.h>
using namespace std;
int main()
{
map<string, int> mm;//Map中的元素是自动按key升序排序,所以不能对map用sort函数:
//插入数据与输出
mm["a"]=1;
mm["qwer"]=78;
mm.insert(pair<string,int>("ppp",2));
mm["asd"]=-7;
mm["ppp"]=78;
cout<<mm["a"]<<endl;
map<string,int>::iterator it;
it=mm.find("qwer");//find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。
cout<<it->second;////first是Key, second是value;
it=mm.find("ppp");
cout<<endl<<it->first<<" "<<it->second;
it=mm.find("112");
if(it==mm.end())//因为没找到会返回最后一个
{
cout<<endl<<"没有找到";
}
else
mm.erase(it);//删除元素
cout<<endl<<mm.max_size();//返回可以容纳的最大元素
cout<<endl<<mm.size()<<endl;
cout<<mm.count("ppp");//返回元素出现的次数 但是不是相同的会删除吗? 所以返回值只能是1和0 可以来判断存不存在
}
容器适配器
①stack
stack 模板类的定义在<stack>
头文件中。
stack 模板类需要两个模板参数,一个是元素类型,一个容器类型,但只有元素类型是必要的,在不指定容器类型时,默认的容器类型为deque。
定义stack 对象的示例代码如下:
stack<int> s1;
stack<string> s2;
stack 的基本操作有:
s.push(x);
//入栈
s.pop();
//出栈,注意,出栈操作只是删除栈顶元素,并不返回该元素。
s.top();
//访问栈顶,但不删除该元素
s.empty();
//判断栈空,当栈空时,返回true。
s.size();
//访问栈中的元素个数
②queue
queue 模板类的定义在<queue>
头文件中。
与stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
定义queue 对象的示例代码如下:
queue<int> q1;
queue<double> q2;
queue 的基本操作有:
q.push(x);
//入队,将x 接到队列的末端。
q.pop();
//出队,弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
q.front();
//访问队首元素,即最早被压入队列的元素。
q.back();
//访问队尾元素,即最后被压入队列的元素。
q.empty();
//判断队列空,当队列空时,返回true。
q.size();
//访问队列中的元素个数
stack栈顶是top,queue队首是front;
③priority_queue(优先队列)
priority_queue 模板类的定义在<queue>头文件中。
优先队列与队列的差别在于优先队列不是按照入队的顺序出队,而是按照队列中元素的优先权顺序出队(默认为大者优先,也可以通过指定算子
来指定自己的优先顺序)。
priority_queue 模板类有三个模板参数
第一个是元素类型
第二个容器类型
第三个是比较算子
其中后两个都可以省略,默认容器为vector,默认算子为less,即小的往前排,大的往后排(出队时为列尾的元素出队)。
定义priority_queue 对象的示例代码如下:
priority_queue<int> q1;
priority_queue< pair<int, int> > q2;
// 注意在两个尖括号之间一定要留空格。
priority_queue<int, vector<int>, greater<int> > q3;
// 定义小的先出队
priority_queue 的基本操作与queue 相同。
初学者在使用priority_queue 时,最困难的可能就是如何定义比较算子了。
如果是基本数据类型,或已定义了比较运算符的类,
可以直接用STL 的less 算子和greater算子——默认为使用less 算子,即小的往前排,大的先出队。
如果要定义自己的比较算子,方法有多种,这里其中的一种:重载比较运算符。
优先队列试图将两个元素x 和y 代入比较运算符(对less 算子,调用x<y,对greater 算子,调用x>y),
若结果为真,则x 排在y 前面,y 将先于x 出队,反之,则将y 排在x 前面,x 将先出队。
下面几种重载运算符方法:
1.重载为友元函数:
struct node
{
int x;
int y;
//要求按y大的排序,y相同x小的排序
friend bool operator <(const node &a,const node &b) //对应less算子
{
if(a.y==b.y)
return a.x>b.x; //x大的排在前,则出队时x小的先出队
else
return a.y<b.y; //y小的排在前,则出队时y大的先出队
}
friend bool operator >(const node &a,const node &b) //对应greater算子
{
if(a.y==b.y)
return a.x>b.x;
else
return a.y<b.y;
}
}Node;
2.重载为外部函数
struct node
{
int x;
int y;
//要求按y大的排序,y相同x小的排序
}Node;
bool operator <(const node &a,const node &b) //对应less算子
{
if(a.y==b.y)
return a.x>b.x; //x大的排在前,则出队时x小的先出队
else
return a.y<b.y; //y小的排在前,则出队时y大的先出队
}
bool operator >(const node &a,const node &b) //对应greater算子
{
if(a.y==b.y)
return a.x>b.x;
else
return a.y<b.y;
}