C++常用容器复习

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;
}

参考文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容