【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

更多算法例题链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题)

C++ 内置模板(STL)

迭代器讲解

什么是迭代器(iterator)

迭代器(iterator)的定义:迭代器是一种检查容器内元素并遍历元素的数据类型。
迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。
容器vectorstring有迭代器类型同时拥有返回迭代器的成员。

如:容器有成员 .begin() .end(),其中 .begin() 成员复制返回指向第一个元素的迭代器,即指向第一个元素的“地址”,而 .end() 成员返回指向容器尾元素的下一个位置的迭代器.
.begin() 指向的是第一个合法元素的位置,.end() 指向是容器后第一个不合法元素的地址。

示例
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main()
{
    vector<int> nums;
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(4);
    nums.push_back(8);
    nums.push_back(16);

    vector<string> fruits;
    fruits.push_back("orange");
    fruits.push_back("apple");
    fruits.push_back("raspberry");

    vector<char> empty;

    // 求和 vector nums 中的所有整数(若存在),仅打印结果。
    int sum = 0;
    for (vector<int>::iterator it = nums.begin(); it != nums.end(); ++it)
        sum += *it;
    cout << "Sum of nums: " << sum << "\n";

    // 打印 vector fruits 中的首个 fruis ,不检查是否有一个。
    if (!fruits.empty())
        cout << "First fruit: " << fruits.front() << "\n";

    if (empty.empty())
        cout << "vector 'empty' is indeed empty.\n";
    
    return 0;
}

/*输出:
Sum of nums: 31
First fruit: orange
vector 'empty' is indeed empty
*/

相应的还有容器反向迭代器成员 .rbegin() .rend().rbegin() 返回容器的元素前最后一个不合法的地址,rend() 返回容器的最后一个合法地址。
在这里插入图片描述

容器迭代器的使用

每种容器类型都定义了自己的迭代器类型:
vector:vector<int>::iterator iter;//定义一个名为iter的变量

数据类型是由vector<int>定义的 iterator 类型。简单说就是容器类定义了自己的 iterator 类型,用于访问容器内的元素。每个容器定义了一种名为iterator的类型,这种类型支持迭代器的各种行为。

容器(vector)(线性表的使用)

Vector 容器(类:线性表中有 vectorlist,两者作用比较相似。vector 的主要作用就是可变长度的数组,就把他当成数组使用即可。

#include <iostream>
#include <vector>
 
int main()
{
    // 创建含有整数的 vector
    std::vector<int> v = {7, 5, 16, 8};
 
    // 将二个整数添加到 vector
    v.push_back(25);
    v.push_back(13);
 
    // 迭代并打印 vector 的值
    std::cout << "v = { ";
    for (int n : v)
        std::cout << n << ", ";
    std::cout << "};\n";
}

/*输出:
v = { 7, 5, 16, 8, 25, 13, };
*/
  1. vector容器的定义
#include <vector>   //头文件
vector<int> a;      //定义了一个int类型的vector容器a
vector<int> b[100]; //定义了一个int类型的vector容器b组

struct rec
{
    ···
};

vector<rec> c;            //定义了一个rec类型的vector容器c
vector<int>::iterator it; //vector的迭代器,与指针类似

  1. vector容器的操作
a.size()           //返回实际长度(元素个数),O(1)复杂度
a.empty()      //容器为空返回1,否则返回0,O(1)复杂度
a.clear()      //把vector清空
a.begin()      //返回指向第一个元素的迭代器,*a.begin()与a[0]作用相同
a.end()        //越界访问,指向vector尾部,指向第n个元素再往后的边界
a.front()      //返回第一个元素的值,等价于*a.begin和a[0]
a.back()       //返回最后一个元素的值,等价于*--a.end()和a[size()-1]
a.push_back(x) //把元素x插入vector尾部
a.pop_back()   //删除vector中最后一个元素
  1. 遍历容器的方法

(1)迭代器使用与指针类似,可如下遍历整个容器。

 for ( vector<int>::iterator it=a.begin() ; it!=a.end() ; it++ )
    cout<<*iterator<<endl;

(2) 当成数组使用。

for( int i=0;i<a.size();i++) cout<<a[i]<<endl;

代码示例:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    // 创建含有整数的 vector
    vector<int> v ;
    v.push_back(7);
    v.push_back(5);
    v.push_back(16);
    v.push_back(8);
 
    // 将二个整数添加到 vector
    v.push_back(25);
    v.push_back(13);
 
    // 迭代并打印 vector 的值
    cout << "v = { ";
    for ( vector<int>::iterator it=v.begin() ; it!=v.end() ; it++ )
        cout << *it << ", ";
    cout << "};\n";
    cout << "v = { ";
    for (int j = 0; j < v.size(); ++j) {
            cout << v[j] << ", ";
        }
    cout << "};\n";
}

队列的使用

队列的使用:
1.queue的定义方法

queue<string> myqueue;
queue<int> myqueue_int;
  1. queue的基本操作
front():返回 queue 中第一个元素的引用。
back():返回 queue 中最后一个元素的引用。
push(const T& obj):在 queue 的尾部添加一个元素的副本。
pop():删除 queue 中的第一个元素。
size():返回 queue 中元素的个数。
empty():如果 queue 中没有元素的话,返回 true

集合(set)的使用

在C++中,set是一个基于红黑树实现的关联容器,它可以自动将元素排序并保持唯一性。默认情况下,set使用元素类型的<运算符来比较和排序其元素。如果你想要一个自定义的排序准则,可以在声明set时指定一个比较函数或函数对象。

#include <bits/stdc++.h>
using namespace std;

// 1.set 的定义 set<数据类型> 变量名

set<int> intSet;
set<string> stringSet;

int main()
{
    string s1="测试1";
    string s2="测试2";
    string s3="测试3";

    //2. 插入操作
    stringSet.insert(s3);
    stringSet.insert(s1);

    //5. 返回集合元素数量
    printf("前2次插入操作完成后的元素数量为%d\n",stringSet.size());
    stringSet.insert(s2);
    printf("前3次插入操作完成后的元素数量为%d\n",stringSet.size());

    //6.遍历整个集合,借助迭代器实现
    //定义方式   容器类型< type> ::iterator name
    set<string> ::iterator  setStringIterator;
    for(setStringIterator=stringSet.begin();setStringIterator!=stringSet.end();setStringIterator++)
        cout<<*setStringIterator<<" ";
    puts("");

    //3. 删除操作
    stringSet.erase(s3);
    printf("删除操作完成后的元素数量为%d\n",stringSet.size());

    for(setStringIterator=stringSet.begin();setStringIterator!=stringSet.end();setStringIterator++)
        cout<<*setStringIterator<<" ";
    puts("");

    //4. 判断是否由此元素
    if(stringSet.count(s2)!=0) cout<<"存在元素"<<s2<<endl;
}

映射(map)的使用

map 是一个关联容器,它提供一对一的 hash。

第一个可以称为关键字(key),每个关键字只能在 map 中出现一次
第二个可能称为该关键字的值(value)

map 以模板(泛型)方式实现,可以存储任意类型的数据,包括使用者自定义的数据类型。Map 主要用于资料一对一映射(one-to-one)的情況,map 在 C++ 的內部的实现自建一颗红黑树,这颗树具有对数据自动排序的功能。在 map 内部所有的数据都是有序的。
比如,像是管理班级内的学生,Key 值为学号,Value 放其他信息的结构体或者类。

  1. map 的定义:
//map的定义
map<char, int> mymap1;
map<string, int> mymap2;
  1. 容量:
int map.size();//查询map中有多少对元素
bool empty();// 查询map是否为空
  1. 插入
    map.insert(make_pair(key,value));
    //或者
    map.insert(pair<char, int>(key, value))
    //或者
    map[key]=value
  1. 遍历
map<string, string>::iterator it;
for (it = mapSet.begin(); it != mapSet.end(); ++it)
{
    cout << "key" << it->first << endl;

    cout << "value" << it->second << endl;
}
  1. 查找
m.count(key)//由于map不包含重复的key,因此m.count(key)取值为0,或者1,表示是否包含。
m.find(key)//返回迭代器,判断是否存在。

整体应用代码示例:

#include<bits/stdc++.h>
//#include<vector>
//#include<stack> 
//#include<string>
//#include<queue> 
//#include<deque>
//#include<map>
using namespace std;

//map是每个键对应一个值
//映射类似于函数的对应关系,每个x对应一个y.

//map特性:map会按照键的顺序从小到大自动排序,键的类型必须可以比较大小
void test01(){
	//初始化定义
	map<int, string> mp;

    // 插入元素
    mp.insert(make_pair(1, "One"));
    mp.insert(make_pair(2, "Two"));
    mp.insert(make_pair(3, "Three"));
    mp.insert(make_pair(4, "Four"));

    // 查看元素是否存在
    if (mp.count(2) > 0) {
        cout << "Key 2 exists!" << endl;
    }

    // 查找元素
    map<int,string>::iterator it = mp.find(3);
    if (it != mp.end()) {
        cout << "Value of key 3: " << it->second << std::endl;
    }

    // 删除元素
    mp.erase(2); // 通过键删除元素
    mp.erase(mp.find(4)); // 通过迭代器删除元素

    // 清空map
    mp.clear();

    // 判断map是否为空
    if (mp.empty()) {
        cout << "Map is empty!" << std::endl;
    }
}

void test02(){
	
	/*mp.find(key) 返回键为key的映射的迭代器 $O(logN) 
	注意:用find函数来定位数据出现位置,它返回一个迭代器。当数据存在时,返回数据所在位置的迭代器,数据不存在时,返回mp.end() 
	mp.erase(it) 删除迭代器对应的键和值O(1)
	mp.erase(key) 根据映射的键删除键和值 O(logN) 
	mp.erase(first,last) 删除左闭右开区间迭代器对应的键和值 O(last-first) 
	mp.size() 返回映射的对数$ O(1)$ mp.clear() 清空map中的所有元素O(N) 
	mp.insert() 插入元素,插入时要构造键值对 
	mp.empty() 如果map为空,返回true,否则返回false 
	mp.begin() 返回指向map第一个元素的迭代器(地址) 
	mp.end() 返回指向map尾部的迭代器(最后一个元素的下一个地址) 
	mp.rbegin() 返回指向map最后一个元素的迭代器(地址) 
	mp.rend() 返回指向map第一个元素前面(上一个)的逆向迭代器(地址) 
	mp.count(key) 查看元素是否存在,因为map中键是唯一的,所以存在返回1,不存在返回0 
	mp.lower_bound() 返回一个迭代器,指向键值>= key的第一个元素 
	mp.upper_bound() 返回一个迭代器,指向键值> key的第一个元素
	*/
}


void test03(){
	map<int,int> mp;
	mp[1] = 2;
	mp[2] = 3;
	mp[3] = 4;
	map<int,int>::iterator it = mp.begin();
	while(it != mp.end()) {
		cout << it->first << " " << it->second << "\n";
		it ++;
	}
	cout<<"******"<<endl;
	map<int,int> mp1;
	mp1[1] = 2;
	mp1[2] = 3;
	mp1[3] = 4;
	map<int,int>::reverse_iterator it1 = mp1.rbegin();
	while(it1 != mp1.rend()) {
		cout << it1->first << " " << it1->second << "\n";
		it1 ++;
	}

}

void test04(){
	map<int, int> m;
    m.insert(make_pair(1, 2));
    m.insert(make_pair(2, 2));
    m.insert(make_pair(1, 2));
    m.insert(make_pair(8, 2));
    m.insert(make_pair(6, 2));
	map<int, int>::iterator it1 = m.lower_bound(2); 
	cout << it1->first << "\n";//it1->first=2 
	map<int, int>::iterator it2 = m.upper_bound(2); 
	cout << it2->first << "\n";//it2->first=6
	//?? 为什么不是8 
	cout<<"***"<<endl;
	
	map<int,int>::iterator it = m.begin();
	while(it != m.end()) {
		cout << it->first << " " << it->second << "\n";
		it ++;
	}

}

int main()
{
	cout<<"test01():"<<endl;
	test01();
	cout<<"************"<<endl;
	cout<<"test02():"<<endl;
	test02();
	cout<<"************"<<endl;
	cout<<"test03():"<<endl;
	test03();
	cout<<"************"<<endl;
	cout<<"test04():"<<endl;
	test04();
	
	return 0;
}

算法设计例题

例题一:(容器vector)快递的分拣

在这里插入图片描述

样例:
输入:

10 
10124214 北京
12421565  上海
sdafasdg213 天津
fasdfga124 北京
145252  上海
235wtdfsg 济南
3242356fgdfsg 成都
23423 武汉  
23423565f 沈阳
1245dfwfs 成都

输出:

北京 2
10124214
fasdfga124
上海 2
12421565
145252
天津 1
sdafasdg213
济南 1
235wtdfsg
成都 2
3242356fgdfsg 
1245dfwfs 
武汉 1
23423
沈阳 1
23423565f 

题解:

//1. 创建有个vector容器 用来保存地址
vector<string> city;
//2. 再创建一个 用来保存快递单号
vector<string> dig[1000];
//3. 定义一个映射函数,因为城市可能会再次出现,我们需要知道之前有没有。
//4. 读入操作并按照顺序进行存放

题解示例:

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

//创建有个vector容器 用来保存地址
vector<string> city;
//再创建一个 用来保存快递单号
vector<string> dig[1000];

int Myfind(string s){
    //寻找到该城市的位置 下标
    for(int i=0;i<city.size();i++)
    {
        if(city[i]==s) return i;
    }
    return -1;
}

int main()
{

    int n;
    cin>>n;//输入有几个快递

    for(int i=0;i<n;i++)
    {
        string d,c;
        
        cin>>d>>c;///输入快递单号 和 快递地址
        int flag=Myfind(c);//输出该地址的位置
        if(flag==-1){//如果没找到这个地址
            city.push_back(c);//把这个城市添加到city这个容器中 
            dig[city.size()-1].push_back(d);//在对应位置的数值后添加 快递单号
        }
        else  dig[flag].push_back(d);//在对应位置的数值后添加 快递单号
    }
    for(int i=0;i<city.size();i++)
    {
        cout<<city[i]<<" "<<dig[i].size()<<endl;
        for(int j=0;j<dig[i].size();j++)
            cout<<dig[i][j]<<endl;
    }
}

例题二:(queue)银行排队问题

在这里插入图片描述

输入样例:

5
IN xiaoming N
IN Adel V
IN laozhao N
OUT N
IN CLZ V

输出样例:

Adel
CLZ
laozhao

题解:

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

queue<string> V; // VIP队列
queue<string> N; // 普通队列

int main()
{
    int M;
    cin >> M; // 输入操作的次数

    while (M--) // 每次进行一个操作
    {
        string op, name, type;
        cin >> op; // 读入 进入还是出去
        if (op == "IN")
        {
            cin >> name >> type; // 读取名字 和 类型

            if (type == "V")
                V.push(name); // 如果是VIP类型,加入VIP队列
            else
                N.push(name); // 否则加入普通队列
        }
        else
        {
            cin >> type; // 读取类型

            if (type == "V")
                V.pop(); // 如果是VIP类型,从VIP队列出队
            else
                N.pop(); // 否则从普通队列出队
        }
    }

    // 打印结果
    while (V.size())
    {
        cout << V.front() << endl; // 输出VIP队列中的元素
        V.pop(); // 出队
    }
    while (N.size())
    {
        cout << N.front() << endl; // 输出普通队列中的元素
        N.pop(); // 出队
    }

    return 0;
}

例题三:(map)重复的单词

在这里插入图片描述

输入样例:

5
sdfggfds
fgsdhsdf
dsfhsdhr
sdfhdfh
sdfggfds

输出

sdfggfds

题解:

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

map<string,bool> mp;
int main ()
{

    int n;
    string ans="NO";
    cin>>n;
    for(int i=0;i<n;i++)
    {
        string word;
        cin>>word;
        if(mp.count(word)){
            ans=word;
            break;
        }

        else mp[word]=1;
    }
    cout<<ans<<endl;

}

感谢阅读!!!
更多算法例题链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题)

  • 42
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Chen_devy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值