STL学习——栈,队列,set,优先队列

栈:

stack容器内元素的访问
​由于栈(stack)本身就是一种后进先出的数据结构。在STL中stack中只能通过top()来访问栈顶元素

栈上的基本操作
栈的基本操作包括:

函数名 用途
push(x) 将x入栈
top() 获得栈顶元素
pop() 用以弹出栈顶元素
empty() 可以检测stack内是否为空,返回true为空,返回false为非空
size() 返回stack内元素的个数


队列:

队列遵循先进先出,后进后出,使用上和栈stack类似

队列函数调用

函数名 使用介绍
q.pop() 删除queue的队头元素
q.front() 返回队列的队头元素,但不删除该元素
q.back() 返回队列的队尾元素,但不删除该元素
q.push(arg) 将元素arg插入到队列的队尾
q.emplace(arg) 将元素arg放置到队列的尾部,作用和push一样
q.size() 返回队列中元素的个数
q.empty() 当队列为空时返回true,否则返回false
q.swap(q1) 交换q和q1中的元素,方法和stack中一样,并不会真正使用拷贝形式进行交换,只是交换底层的数据结构
swap(q,q1) 非成员函数,和成员函数swap一样


set:

set 的含义是集合,它是一个有序的容器,里面的元素都是排序好的,支持插入,删除,查找等操作,就像一个集合一样。所有的操作的都是严格在logn时间之内完成,效率非常高。set 和 multiset 的区别是:set 插入的元素不能相同,但是 multiset 可以相同。其特点如下:

  1. 每个元素的键值都唯一,不允许两个元素有相同的键值。
  2. 所有元素都会根据元素的键值自动排序(默认从小到大)。
  3. set 中的元素不像 map 那样可以同时拥有实值(value)和键值(key),只能存储键,是单纯的键的集合。
  4. set 中元素的值不能直接被改变。
  5. set 支持大部分的map的操作,但是 set 不支持下标的操作,而且没有定义mapped_type类型。

set基本操作

1.set 的定义及初始化

set<Type> s						      //定义一个set容器
set<Type> s(s1)			              //定义一个set容器,并用容器s1来初始化
set<Type> s(b, e)					  //b和e分别为迭代器的开始和结束的标记
set<Type> s(s1.begin(), s1.begin()+3) //用容器s1的第0个到第2个值初始化s
set<Type> s(a, a + 5)      		      //将a数组的元素初始化vec向量,不包括a[4]
set<Type> s(&a[1], &a[4]) 			  //将a[1]~a[4]范围内的元素作为s的初始值

2.set 的基本操作

s.begin()					//返回指向第一个元素的迭代器
s.end()						//返回指向最后一个元素的迭代器
s.clear()					//清除所有元素
s.count()					//返回某个值元素的个数
s.empty()					//如果集合为空,返回true,否则返回false
s.equal_range()				//返回集合中与给定值相等的上下限的两个迭代器
s.erase()					//删除集合中的元素
s.find(k)					//返回一个指向被查找到元素的迭代器
s.insert()					//在集合中插入元素
s.lower_bound(k)			//返回一个迭代器,指向键值大于等于k的第一个元素
s.upper_bound(k)			//返回一个迭代器,指向键值大于k的第一个元素
s.max_size()				//返回集合能容纳的元素的最大限值
s.rbegin()					//返回指向集合中最后一个元素的反向迭代器
s.rend()					//返回指向集合中第一个元素的反向迭代器
s.size()					//集合中元素的数目

set用法:

1.基本用法

#include <iostream>
#include <set>
using namespace std;
int main(){
     set<int> s;
     s.insert(1);
     s.insert(2);
     s.insert(3);
     s.insert(1);
     cout<<"set的size值为 :"<<s.size()<<endl;
     cout<<"set的maxsize的值为 :"<<s.max_size()<<endl;
     cout<<"set中的第一个元素是 :"<<*s.begin()<<endl;
     s.clear();
     if(s.empty())
         cout<<"set为空"<<endl;
     cout<<"set的size值为 :"<<s.size()<<endl;
     cout<<"set的maxsize的值为 :"<<s.max_size()<<endl;
     return 0;
}

set.end()不是最后一个元素,它指向最后元素的后一位。
这样可以常用来遍历set。
实际上它效果上等同与set.size()
如果是{1, 55, 99999},那么set.size() == set.end() == 3

  1. 插入3之后虽然插入了一个1,但set中最后一个值仍然是3 。一共插入了4个数,但是集合中只有3个数并且是有序的,说明了set集合的两个特点,有序和不重复。
  2. begin() 和 end()函数是不检查set是否为空的,使用前最好使用empty()检验一下set是否为空。

2.count() 的用法

//返回某个值元素的个数
#include <iostream>
#include <set>
using namespace std;
int main(){
     set<int> s;
     s.insert(1);
     s.insert(2);
     s.insert(3);
     s.insert(1);
     cout<<"set 中 1 出现的次数是 :"<<s.count(1)<<endl;
     cout<<"set 中 4 出现的次数是 :"<<s.count(4)<<endl;
     return 0;
}

总结: count() 用来查找set中某个键值出现的次数,但因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了,所以这个函数在set中并不是很实用。

3.erase() 的用法

  1. erase(iterator) :删除定位器iterator指向的值

  2. erase(first,second):删除定位器first和second之间的值

  3. erase(key_value):删除键值key_value的值

#include <iostream>
#include <set>
using namespace std;
int main(){
     set<int> s;
     set<int>::const_iterator it;
     set<int>::iterator first;
     set<int>::iterator second;
     for(int i=1; i<=10; ++i)
         s.insert(i);
     //第一种删除,删掉1
     s.erase(s.begin());
     //第二种删除,删掉2和3
     first = s.begin();
     second = s.begin();
     second++;
     second++;
     s.erase(first,second);
     //第三种删除,删掉8
     s.erase(8);
     cout<<"删除后 set 中元素是 :";
     for(it=s.begin(); it!=s.end(); ++it)
         cout<<*it<<" ";
     cout<<endl;
     return 0;
}

总结: set中的删除操作是不进行任何的错误检查的,比如定位器的是否合法等等,所以用的时候自己一定要注意。

4.find() 的用法

//返回一个指向被查找到元素的迭代器,如果没找到则返回end()
#include <iostream>
#include <set>
using namespace std;
int main(){
     int a[] = {4,5,6};
     set<int> s(a,a+3);
     set<int>::iterator it;
     if((it=s.find(4))!=s.end())
         cout<<*it<<endl;
     return 0;
}

输出结果

4

5.insert() 的用法

  1. insert(key_value):将key_value插入到set中 ,返回值是pair<set: :iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置;若key_value已经在set中,则iterator表示的key_value在set中的位置。

  2. inset(first,second);将定位器first到second之间的元素插入到set中,返回值是void.

#include <iostream>
#include <set>
using namespace std;
int main(){
     int a[] = {1,2,3};
     set<int> s;
     set<int>::iterator it;
     s.insert(a,a+3);
     for(it=s.begin(); it!=s.end(); ++it)
         cout<<*it<<" ";
     cout<<endl;
     pair<set<int>::iterator,bool> pr;
     pr=s.insert(5);
     if(pr.second)
         cout<<*pr.first<<endl;
     cout<<"插入数值之后的set中有:"<<endl;
	 for(it=s.begin(); it!=s.end(); ++it)
		cout<<*it<<" ";
	 cout<<endl;
     return 0;
}

6.lower_bound()、upper_bound() 的用法

  1. lower_bound(key_value) :返回第一个大于等于key_value的定位器

  2. upper_bound(key_value):返回第一个大于key_value的定位器

#include <iostream>
#include <set>
using namespace std;
int main(){
     set<int> s;
     s.insert(1);
     s.insert(3);
     s.insert(4);
     s.insert(6);
     cout<<*s.lower_bound(1)<<endl;
     cout<<*s.lower_bound(2)<<endl;
     cout<<*s.upper_bound(3)<<endl;
     return 0;
}

输出结果:

1
3
4

7.equal_range() 的用法

equal_range():返回一对定位器,分别表示第一个大于等于给定关键值的元素和第一个大于给定关键值的元素,这个返回值是一个pair类型。如果这一对定位器中哪个返回失败,就会等于end()的值。

#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int main(){
	set<int> s;
	set<int>::iterator it;
	for(int i=1; i<=5; ++i)
		s.insert(i); //向set中加入数据
	for(it=s.begin(); it!=s.end(); ++it)
		cout<<*it<<" ";  //输出set中的数据
	cout<<endl;
	pair<set<int>::const_iterator,set<int>::const_iterator> pr;
	pr=s.equal_range(3);
	cout<<"第一个大于等于3的数是:"<<*pr.first<<endl;
	cout<<"第一个大于3的数是: "<<*pr.second<<endl;
	return 0;
}

8.自定义比较函数
(1). 元素不是结构体:

 //自定义比较函数myComp,重载“()”操作符
struct myComp{
	bool operator()(const your_type &a,const your_type &b){
		return a.data > b.data;
	}
}
set<int,myComp>s;
set<int,myComp>::iterator it;

(2). 元素是结构体:

//可以直接将比较函数写在结构体内
struct Info{
	string name;
	float score;
	//重载“<”操作符,自定义排序规则
	bool operator < (const Info &a) const{
		//按score从大到小排列
		return a.score<score;
	}
}
 
set<Info> s;
set<Info>::iterator it;


优先队列:

和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队

优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的

和队列基本操作相同:

· top 访问队头元素
· empty 队列是否为空
· size 返回队列内元素个数
· push 插入元素到队尾 (并排序)
· emplace 原地构造一个元素并插入队列
· pop 弹出队头元素
· swap 交换内容

定义:priority_queue<Type, Container, Functional>
Type 就是数据类型
Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector)
Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆

一般是:

//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数
//(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

基本类型例子:

#include<iostream>
#include <queue>
using namespace std;
int main() 
{
    //对于基础类型 默认是大顶堆
    priority_queue<int> a; 
    //等同于 priority_queue<int, vector<int>, less<int> > a;
    
  
    priority_queue<int, vector<int>, greater<int> > c;  //这样就是小顶堆
    priority_queue<string> b;

    for (int i = 0; i < 5; i++) 
    {
        a.push(i);
        c.push(i);
    }
    while (!a.empty()) 
    {
        cout << a.top() << ' ';
        a.pop();
    } 
    cout << endl;

    while (!c.empty()) 
    {
        cout << c.top() << ' ';
        c.pop();
    }
    cout << endl;

    b.push("abc");
    b.push("abcd");
    b.push("cbd");
    while (!b.empty()) 
    {
        cout << b.top() << ' ';
        b.pop();
    } 
    cout << endl;
    return 0;
}

输出:

4 3 2 1 0
0 1 2 3 4
cbd abcd abc

pari的比较,先比较第一个元素,第一个相等比较第二个

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main() 
{
    priority_queue<pair<int, int> > a;
    pair<int, int> b(1, 2);
    pair<int, int> c(1, 3);
    pair<int, int> d(2, 5);
    a.push(d);
    a.push(c);
    a.push(b);
    while (!a.empty()) 
    {
        cout << a.top().first << ' ' << a.top().second << '\n';
        a.pop();
    }
}

输出:

2 5
1 3
1 2

对于自定义类型

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

//方法1
struct tmp1 //运算符重载<
{
    int x;
    tmp1(int a) {x = a;}
    bool operator<(const tmp1& a) const
    {
        return x < a.x; //大顶堆
    }
};

//方法2
struct tmp2 //重写仿函数
{
    bool operator() (tmp1 a, tmp1 b) 
    {
        return a.x < b.x; //大顶堆
    }
};

int main() 
{
    tmp1 a(1);
    tmp1 b(2);
    tmp1 c(3);
    priority_queue<tmp1> d;
    d.push(b);
    d.push(c);
    d.push(a);
    while (!d.empty()) 
    {
        cout << d.top().x << '\n';
        d.pop();
    }
    cout << endl;

    priority_queue<tmp1, vector<tmp1>, tmp2> f;
    f.push(c);
    f.push(b);
    f.push(a);
    while (!f.empty()) 
    {
        cout << f.top().x << '\n';
        f.pop();
    }
}

输出:

3
2
1

3
2
1

L2-2 含茶量
分数 25
作者 陈越
单位 浙江大学

https://pintia.cn/problem-sets/1780145616526991360/exam/problems/1780145656624533504?type=7&page=0

#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<stack>
#include<string>
#include<queue>
#include<cctype>
#include<map>
#include<unordered_map>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
struct ide{
	string id;
	string s;
};
struct cmp
{
	bool operator()(const pair<string, int>& p1, const pair<string, int>& p2)
	{
		if (p1.second == p2.second) return p1.first < p2.first;
		return p1.second > p2.second;
	}
};

signed main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int n;
	cin>>n;
	priority_queue<pair<string,int>,vector<pair<string,int>>,cmp>p;
	unordered_map<string,int>u;
	for(int i = 0;i <n; i++)
	{
		string s1,s2;
		cin>>s1;
		cin.ignore();
		getline(cin,s2);
		for(int j=0;j<s2.size();j++)
		{
			if(s2[j]>='A'&&s2[j]<= 'Z')
			{
				s2[j]+=32;
			}
		}
		string temp=s2;
		int cnt=0;
		int index=0;
		int n=s2.size();
		while(index!=-1)
		{
			index=temp.find("chatgpt");
			if(index!=-1)
			{
				cnt++;
				temp=temp.substr(index+1);
			}
		}
		u[s1]+=cnt;
	}
	for(auto&e:u)
	{
		p.push(e);
		if(p.size()>3)
			p.pop();	
	}
	vector<pair<string,int>>vp;
	while(p.size()>0)
	{
		pair<string,int>tmp=p.top();
		p.pop();
		vp.push_back(tmp);
	}
	while(vp.size()>0)
	{
		if(vp.back().second>0)
		{
			cout<<vp.back().first<<" "<<vp.back().second<<endl;
		}
		vp.pop_back();
	}
	return 0;
}
posted @ 2024-04-14 16:36  miao-jc  阅读(17)  评论(0编辑  收藏  举报