【C++笔记】十九、标准模板库(STL)(中)

1.STL中的容器

  • 序列容器

vector,(优点)允许容器元素随机存取,允许通过数组的方式引用容器中的元素值。(缺点)但在容器的中间部位插入或删除容器的元素的代价是比较大的。

list,基于双向链表的,要定位某一元素的话,就需要从首节点一个一个遍历,直到遍历到目标node为止。优缺点和vector正好相反

deque,双端队列

forward_list(C++11),基于单向链表

queue,队列,先入先出

priority_queue,优先队列,总是将队列中最大的值放到队首

stack,栈

  • 有序关联容器

set,集合,不允许重复的值,类型要都一样

multiset,允许有重复值

map,不允许key重复

multimap,允许key重复

  • 无序关联容器(C++11),使用哈希的存储方式,通过key定位

unordered_set

unordered_multiset

unordered_map

unordered_multimap

2.双向链表容器类 list

#include <iostream>
#include <list>
using namespace std;
void output(int value)
{
    cout << value << " ";
}
bool removeIf(int value)
{
    if(value % 2 == 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}
bool compareInt(int n1, int n2)
{
    if(n1 >= n2)
    {
        return true;
    }
    else
    {
        return false;
    }
    
}
int main(int argc, const char * argv[]) {
    // 双向链表容器类:list
    // vector<int> v;  v[1]
    // list不允许像vector一样使用数组的方式随机访问元素值
    
    // insert O(1)
    // remove
    // remove_if
    // sort    // NLogN
    // splice
    // merge://  被合并的两个链表最好是已经被排序的
    // unique:去掉list中重复的值

    //  vector:随机访问
    //  list:插入和删除
    
    list<int> one(10, 3);
    for_each(one.begin(), one.end(), output);
    cout << endl; // 3 3 3 3 3 3 3 3 3 3 
    
    //  插入
    list<int> two;
    int intArray[]{1,2,3,4,5,6};
    two.insert(two.begin(), intArray, intArray + 6);//此时two是 1 2 3 4 5 6从two的开头开始插入,插入intArray的第一个到第6个范围的数值
    two.insert(two.end(), 100); // 此时two是 1 2 3 4 5 6 100
    two.insert(two.begin(), 200); // 此时two是 200 1 2 3 4 5 6 100
    for_each(two.begin(), two.end(), output);
    cout << endl;  // 200 1 2 3 4 5 6 100
    
    //  删除
    two.remove(4);   //  参数是元素值,不是索引,即将4这个值从two中找到并删除
    for_each(two.begin(), two.end(), output);
    cout << endl; // 200 1 2 3 5 6 100
    
    two.remove_if(removeIf); // 参数是函数,把能被2整除的数都删除
    for_each(two.begin(), two.end(), output);
    cout << endl; // 1 3 5
    
    //  排序
    two.sort(compareInt);  //  降序排列
    for_each(two.begin(), two.end(), output);
    cout << endl;  // 5 3 1
    
    // splice
    two.splice(two.begin(), one);  // 将one插到two的最开始位置,list<int> one(10, 3);
    for_each(two.begin(), two.end(), output);
    cout << endl; // 3 3 3 3 3 3 3 3 3 3 5 3 1
    
    //  去掉重复的,O(N)
    two.unique();           //  去掉相邻元素重复的值
    for_each(two.begin(), two.end(), output);
    cout << endl;  // 3 5 3 1
    
    for_each(one.begin(), one.end(), output);
    cout << endl;  // 此时one为空,因为splice是移动元素,不是复制元素
    
    // merge
    one.insert(one.begin(), intArray + 3, intArray + 6);  // 此时one是 4,5,6
    
    two.sort(); // 1 3 3 5
    two.unique(); 
    for_each(two.begin(), two.end(), output);
    cout << endl; // 1 3 5 
    
    two.merge(one);  // merge:将有序的one,合并到有序的two中
    for_each(two.begin(), two.end(), output);
    cout << endl; // 1 3 4 5 5 6
    
    two.unique();
    for_each(two.begin(), two.end(), output);
    cout << endl; // 1 3 4 5 6 
    return 0;
}

3.同时兼具vector和list优势的双端队列deque

#include <iostream>
#include <deque>
using namespace std;
int main(int argc, const char * argv[]) {
    // 同时兼具vector和list优势的双端队列:deque
    
    deque<int> values {1,2,3,4,5};
    cout << values[2] << endl;  // 3
    
    values.erase(values.begin()); 
    cout << values[0] << endl;  // 2
    
    values.insert(values.begin(), 20);
    cout << values[0] << endl;  // 20
    
    values.erase(values.end() - 1);
    cout << *(values.end() - 1) << endl;  // 4
    
    return 0;
}

4.单向链表容器forward_list(C++11)

#include <iostream>
#include <forward_list>
#include <list>
using namespace std;

int main(int argc, const char * argv[]) {
    // 单链表容器:forward_list(C++ 11)
    // list:双向链表,支持从尾节点往前遍历
    // 对于链表来说,不能对迭代器+1或-1来访问元素,因为这就属于随机访问了,链表是不支持的
    list<int> list_values {1,2,3,4,5};
    for(auto it = list_values.rbegin(); it != list_values.rend(); it++) // rbegin和rend,逆向遍历
    {
        cout << *it << " ";
    }
    cout << endl;  // 5 4 3 2 1
    
    forward_list<int> forward_list_values{1,2,3,4,5};
    for(auto it = forward_list_values.begin(); it != forward_list_values.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl; // 1 2 3 4 5
    
    return 0;
}

5.队列容器queue

#include <iostream>
#include <queue>
using namespace std;

int main(int argc, const char * argv[]) {
    // 队列容器类:queue,先进先出
    
    queue<int> q;// queue<int> q {1,2,3,4,5}  error; 只能将数一个一个的压入队列中
    q.push(10);
    q.push(20); // 在10出队之前,我们不能访问这个20
    q.push(30);
    
    //  获得队首元素值
    cout << q.front() << endl; //  10 front返回的不是迭代器,是元素值
    
    //  获取队尾元素值
    cout << q.back() << endl;  // 30 
    
    // q[2]; 报错,不能索引
    
    q.pop();  // 出队 队首元素
    cout << q.front() << endl;  // 20
    
    cout << q.size() << endl;   // 2
    
    q.pop();
    q.pop();
    cout << (q.empty()?"true":"false") << endl;  // true

    return 0;
}

6.永远获得最大值的的队列容器类priority_queue

#include <iostream>
#include <queue>
using namespace std;

int main(int argc, const char * argv[]) {
    // 永远获得最大值的队列容器类:priority_queue,出队的值永远是队列中的最大值
    
    priority_queue<int> p;
    p.push(10);
    p.push(20);
    p.push(30);
    
    cout << p.top() << endl;  // 30
    
    p.pop();
    
    cout << p.top() << endl;  // 20
    
    return 0;
}

7.栈容器类stack

#include <iostream>
#include <stack>
using namespace std;
int main(int argc, const char * argv[]) {
	
    // 栈容器类:stack
    stack<int> stack_int;
    stack_int.push(10);
    stack_int.push(20);
    stack_int.push(30); // 将容器倒过来去理解,就像一个水桶,往水桶里push
    
    cout << stack_int.top() << endl;   // 30
    
    stack_int.pop();   
    
    cout << stack_int.top() << endl;  //  20
    
    cout << stack_int.size() << endl;  //  2
    
    cout << stack_int.empty() << endl; //  0

    return 0;
}

8.数组模板类array

#include <iostream>
#include <array>
using namespace std;
void output(int n)
{
    cout << n << " ";
}
int main(int argc, const char * argv[]) {
    // 数组模板类array
    // 没有insert,push_back等方法
    
    // 有:[],at,begin,end
    
    array<int, 5> array_int {1,2,3,4,5};
    
    for_each(array_int.begin(), array_int.end(), output);
    cout << endl;  // 1 2 3 4 5
    for_each(array_int.rbegin(), array_int.rend(), output);
    cout << endl; // 5 4 3 2 1 
    
    cout << array_int[2] << endl;  // 3
    
    cout << array_int.at(3) << endl;  // 4,第四个数组元素
    
    cout <<array_int.size() << endl; // 5

    return 0;
}

9.集合容器类set

#include <iostream>
#include <set>
#include <array>
using namespace std;

void output(string s)
{
    cout << s << " ";
}

int main(int argc, const char * argv[]) {
    // 集合容器类:set
    
    // 集合的特点:元素是唯一的,不能重复
    // 插入、copy、合并、交集
    
    set<string> set1 {"Bill", "Mike"};
   // set1.insert("John");
    set1.insert("Bill");  // 添加了重复值,集合大小不变
    cout << set1.size() << endl; // 2
    
    // copy
    array<string, 2> array_string; 
    copy(set1.begin(), set1.end(), array_string.begin());
    for_each(array_string.begin(), array_string.end(), output);
    cout << endl;   // Bill Mike
    
    set<string> set2;
    copy(set1.begin(), set1.end(), insert_iterator<set<string>>(set2, set2.begin())); // 如果第三个参数使用set2.begin()那么系统会将其看作常量,编译会报错,就不能插入了,所以要用插入迭代器
    for_each(set2.begin(), set2.end(), output);
    cout << endl;  // Bill Mike
    
    //  insert
    set2.insert("abc");
    set2.insert("ok");
    for_each(set2.begin(), set2.end(), output);
    cout << endl;  // Bill Mike abc ok
    
    //  取交集
    set<string> set3;  // set1 set2取交集存到set3,set3也要用到insert迭代器
    set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), insert_iterator<set<string>>(set3,set3.begin()));
    for_each(set3.begin(), set3.end(), output);
    cout << endl; // Bill Mike
    
    //  union
    set<string> set4;
    set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), insert_iterator<set<string>>(set4,set4.begin()));
    for_each(set4.begin(), set4.end(), output);
    cout << endl;  // Bill Mike abc ok
    
    return 0;
}

10.支持重复值的集合容器类multiset

#include <iostream>
#include <set>
using namespace std;
int main(int argc, const char * argv[]) {
    // 支持重复值的集合容器类:multiset
    
    set<int> values1 {1,2,2,4,5};
    for(auto value:values1)
    {
        cout << value << " ";
    }
    cout << endl; // 1 2 4 5

    multiset<int> values2{1,2,2,4,5};
    for(auto value:values2)
    {
        cout << value << " ";
    }
    cout << endl; // 1 2 2 4 5
    
    return 0;
}

11.映射容器类map

#include <iostream>
#include <map>
using namespace std;

int main(int argc, const char * argv[]) {
    // 映射容器类:map
    //  存储形式:key-value
    //  特点:key不能重复
    map<int, string> persons;  // 参数一是key的类型,参数二是value的类型
    pair<int, string> person1(10, "Bill"); // pair代表map中的每一对儿值
    persons.insert(person1);
    pair<int, string> person2(20, "Mike");
    persons.insert(person2);
    pair<int, string> person3(30, "John");
    persons.insert(person3);
    
    //  first:key
    cout << persons.find(20)->first << endl; // 20 find(20)返回的是指向pair对象的指针,其中first是key值,second是value值
    //  second:value
    cout << persons.find(30)->second << endl; // John
    
    map<int,string>::iterator it = persons.find(35);
    if(it != persons.end())
    {
        cout << "key = " << it->first << " value = " << it->second << endl;
    }
    else
    {
        cout << "没找到!" << endl;  // 没找到!
    }
    
    pair<int,string> person4(20, "Bee");
    cout << "size1 = " << persons.size() << endl;  // 3
    persons.insert(person4);
    cout << "size2 = " << persons.size() << endl;  // 3
    
    cout << persons.find(20)->second << endl;  // Mike,并没有替换
    
    return 0;
}

12.允许key重复的映射容器类multimap

#include <iostream>
#include <map>
using namespace std;
int main(int argc, const char * argv[]) {
    // 允许key重复的映射容器类:multimap
    //  set  multiset
    //  map  multimap

    //  核心问题:如何获取重复的key对应的所有value(3种方法)
    
    multimap<int, string> values;
    pair<int, string> value1(10, "Bill");
    pair<int, string> value2(10, "Mike");
    pair<int, string> value3(10, "Mary");
    pair<int, string> value4(20, "John");
    values.insert(value1);
    values.insert(value2);
    values.insert(value3);
    values.insert(value4);
    cout << values.size() << endl; // 4
    
    cout << values.count(10) << endl;  // 3
    
    //  第1种获取重复的key对应的所有value的方法
    multimap<int, string>::iterator it = values.find(10);
    size_t count = values.count(10);
    for(int i = 0; i < count; i++)
    {
        cout << (*(it++)).second << endl;  // Bill Mike Mary,这里只能用++,用加1的话,不支持随机访问
    }
    
    //  第2种获取重复的key对应的所有value的方法,使用了两个迭代器
    multimap<int, string>::iterator it_lower = values.lower_bound(10);
    multimap<int, string>::iterator it_upper = values.upper_bound(10);
    for(auto it = it_lower; it != it_upper;it++)
    {
        cout << "key = " << it->first << " value = " << it->second << endl;
    }
    
    //  第3种获取重复的key对应的所有value的方法,和第二种方法类似,只不过两个迭代器是同时获得的
    pair<multimap<int, string>::iterator, multimap<int, string>::iterator> range = values.equal_range(10);
    for(auto it = range.first; it != range.second;it++) // first相当于lower,second相当于upper
    {
        cout << "key = " << it->first << " value = " << it->second << endl;
    }
    
    return 0;
}

13.无序关联容器(C++11)

#include <iostream>
#include <unordered_set>
#include <unordered_map>

using namespace std;

int main(int argc, const char * argv[]) {
    // 无序关联容器(C++ 11)
    //  unordered_set、unordered_multiset、unordered_map和unordered_multimap:基于hash,定位查找速度更快
    //  set            multiset            map            multimap :基于树的结构(有序关联容器)
    //
    unordered_set<int> set_int{1,2,3,4,4};
    cout << set_int.size() << endl; // 4 重复的只保留一个

    unordered_multimap<int, string> multimap_int;
    pair<int, string> value1(10, "Bill");
    pair<int, string> value2(10, "Mike");
    pair<int, string> value3(20, "John");
    multimap_int.insert(value1);
    multimap_int.insert(value2);
    multimap_int.insert(value3);
    pair<unordered_multimap<int, string>::iterator, unordered_multimap<int, string>::iterator> range = multimap_int.equal_range(10);
    for(auto it = range.first; it!=range.second;it++)
    {
        cout << it->second << endl;  //  Bill Mike
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DUANDAUNNN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值