您现在的位置是:首页 >技术杂谈 >STL——list、stack与queue网站首页技术杂谈

STL——list、stack与queue

热爱编程的小K 2023-05-28 16:00:02
简介STL——list、stack与queue

在这里插入图片描述

📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段>——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的
📖作者主页:热爱编程的小K
📖专栏链接:c++

🎉欢迎各位→点赞👏 + 收藏💞 + 留言🔔​
💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🐾

在这里插入图片描述


一、list

1、简介

list 容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中。

2、操作基本数据类型

初始化可以直接赋值,也可以不赋值

void testOne() 
{
	list<int> nums = { 1,2,3,4 };
	list<string> str;
	str.push_back("king");
	str.push_back("link");
	for (auto v : str) 
	{
		cout << v << " ";
	}
	cout << endl;
	//删除方式遍历
	while (!str.empty()) 
	{
		cout << str.front() << endl;
		str.pop_front();
	}
}

3、操作自定义类型

记得重载输出运算符,或者提供打印接口

class MM 
{
public:
	MM(string name=" ",int age=0):name(name),age(age){}
	friend ostream& operator<<(ostream& out,const MM& object)
	{
		out << object.age << "	" << object.name << endl;
		return out;
	}
	string getName() const{ return name; }
	int getAge() const{ return age; }
protected:
	string name;
	int age;
};
void testTwo() 
{
	list<MM> mm;
	mm.push_back(MM("king", 18));
	mm.push_back(MM("貂蝉", 28));
	mm.push_back(MM("妲己", 19));
	for (auto v : mm) 
	{
		cout << v;
	}
	cout << endl;

}

4、sort函数的五花八门

sort函数默认的是从小到大排序(less<>()),也可以greater<>()方式进行排序,sort的参数是一个排序准则(后面可以用仿函数,会方便很多),这里我们自己写函数排序准则

bool cmpAge(const MM& one, const MM& two) {
	return one.getAge() < two.getAge();
}
bool cmpName(const MM& one, const MM& two ) {
	return one.getName() < two.getName();
}
void testthree() {
	list<int> nums = { 2,3,8,65,43,0,4 };
	nums.sort();
	for (auto v : nums) {
		cout << v << " ";
	}
	cout << endl;
	nums.sort(less<int>()); //等价于默认
	for (auto v : nums) {
		cout << v << " ";
	}
	cout << endl;
	nums.sort(greater<int>());  //重大到小
	for (auto v : nums) {
		cout << v << " ";
	}
	cout << endl;
	nums.reverse();  //反转
	for (auto v : nums) {
		cout << v << " ";
	}
	cout << endl;
	list<MM> info;
	info.push_back(MM("貂蝉", 18));
	info.push_back(MM("狂铁", 19));
	info.push_back(MM("妲己", 34));
	cout << "按年龄排序" << endl;
	info.sort(cmpAge);
	for (auto v : info) {
		cout << v;
	}
	cout << endl;
	cout << "按姓名排" << endl;
	info.sort(cmpName);
	for (auto v : info) {
		cout << v;
	}
	cout << endl;
}

5、删除操作

当使用一个容器的insert或者erase函数通过迭代器插入或删除元素"可能"会导致迭代器失效,因此我们为了避免危险,应该获取insert或者erase返回的迭代器,以便用重新获取的新的有效的迭代器进行正确的操作

bool find_name(const MM& three, string name) {
	return three.getName() == name;
}
void Test() 
{
	list<MM> info;
	info.push_back(MM("貂蝉", 18));
	info.push_back(MM("狂铁", 19));
	info.push_back(MM("妲己", 34));
	auto iter = find_if(info.begin(), info.end(), bind(find_name, placeholders::_1, "妲己"));
	info.erase(iter);
	for (auto v : info) {
		cout << v;
	}
	cout << endl;
	//迭代器删除
	for (auto i = info.begin(); i != info.end();)
	{
		if (i->getName() == "狂铁") 
		{
			i = info.erase(i);
		}
		else 
		{
			i++;
		}
	}
	for (auto v : info) 
	{
		cout << v;
	}
}

二、stack

1、stack概念

stack是一种容器适配器,专门设计用于在LIFO上下文(后进先出)中操作,在LIFO上下文中,仅从容器的一端插入和提取元素。

stack作为容器适配器实现,它们是使用特定容器类的封装对象作为其基础容器的类,提供了一组特定的成员函数来访问其元素。元素从特定容器的尾部被推入*/弹出,这被称为堆栈的*顶部。

容器应支持以下操作:

  • empty
  • size
  • back
  • push_back
  • pop_back

标准容器类vector,deque 和list满足这些要求。默认情况下,使用标准容器 deque来作为底层容器。

2、简单应用—进制转换

将123转换为二进制

void test1() {
	int nums = 123;
	stack<int> mm;
	while (nums) 
	{
		mm.push(nums % 2);
		nums /= 2;
	}
	while (!mm.empty()) 
	{
		cout << mm.top();
		mm.pop();
	}
}

3、练习—leetcode20.有效的括号

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = “()”
输出:true
示例 2:

输入:s = “()[]{}”
输出:true
示例 3:

输入:s = “(]”
输出:false

提示:

1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-parentheses

题解放在代码中啦

class Solution {
public:
    bool isValid(string s) 
	{
		stack<char> result;
		for (auto v : s) 
		{
			if (v == '(' || v == '[' || v == '{') 
			{
				result.push(v);
			}
			else 
			{
                //列举反例的情况
				if (!result.empty())   //v='}'
				{
					char out = result.top();
					if (v == '}' && out != '{') 
					{
						return false;
					}
					if (v == ']' && out != '[') 
					{
						return false;
					}
					if (v == ')' && out != '(') 
					{
						return false;
					}
                    //括号匹配,出栈
					result.pop();
				}
                //进来的不是左括号,且栈也是空的(进来的是右括号)
				else 
				{
					return false;
				}
			}
		}
        //最后判断栈中还有没有单个元素
		return result.empty();
	}
};

三、queue

1、queue

A、概念

FIFO队列

queue是一种容器适配器,专门设计用于在FIFO上下文中(先进先出)进行操作,在FIFO上下文中,将元素插入到容器的一端,并从另一端提取元素。

queue被实现为容器适配器,它们是使用特定容器类的封装对象作为其基础容器的类,提供了一组特定的成员函数来访问其元素。元素被推入特定容器的*“后部”,并从其“前部”弹出*。

基础容器可以是标准容器类模板之一,也可以是其他一些专门设计的容器类。此基础容器应至少支持以下操作:

  • empty
  • size
  • front
  • back
  • push_back
  • pop_front

标准容器类 deque和list满足这些要求。默认情况下,如果未为特定容器指定容器类队列,类实例化,默认用标准容器 deque

B、操作

//入栈
void push(Type  data);
void pop();

//获取栈顶元素
Type front()
int size();
bool empty();
#include<iostream>
#include<string>
#include<queue>
using namespace std;
void testOne() 
{
	queue<int> mm;
	mm.push(9);
	mm.push(8);
	mm.push(7);
	while (!mm.empty())
	{
		cout << mm.front() << " ";
		mm.pop();
	}
	cout << endl;
}
int main() 
{
	testOne();
	return 0;
}

2、deque

A、概念

deque是“double-ended queue”的缩写,和vector一样都是STL的容器,deque是双端队列,而vector是单端的。

deque在接口上和vector非常相似,在许多操作的地方可以直接替换。

  • deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间添加或删除元素。
  • deque 容器也可以根据需要修改自身的容量和大小。

和 vector 不同的是,deque 还擅长在序列头部添加或删除元素,所耗费的时间复杂度也为常数阶O(1)。并且更重要的一点是,deque 容器中存储元素并不能保证所有元素都存储到连续的内存空间中。

B、操作

class MM 
{
public:
	MM(string name=" ",int age=0):name(name),age(age){}
	void print() const { cout << name << "	" << age << endl; }
	string getName() { return name; }
	int getAge() { return age; }
protected:
	string name;
	int age;
};
void testTwo() 
{
	deque<MM> info;
	info.push_back(MM("貂蝉", 19));
	info.push_back(MM("妲己", 20));
	info.push_back(MM("狂铁", 20));
	while (!info.empty()) {
		info.front().print();
		info.pop_front();
	}
}

3、priority_queue

A、概念

priority_que(优先级队列)是一种容器适配器,经过专门设计,以使其按照某些*严格的弱排序(strict weak ordering)*标准,其第一个元素始终是其中包含的最大元素。

严格是说在判断的时候会用"<",而不是"<=",弱排序是因为,一旦"<“成立便认为存在”<“关系,返回ture,而忽略了”=“关系和”>"区别,把它们归结为false。

此上下文类似于,可以在任何时候插入元素,并且只能检索最大堆元素(优先级队列顶部的元素)。

优先级队列被实现为容器适配器,它们是使用特定容器类的封装对象作为其基础容器的类,提供了一组特定的成员函数来访问其元素。元素被弹出从特定容器的*“后退”,称为优先级队列的顶部*。

基础容器可以是任何标准容器类模板或某些其他专门设计的容器类。该容器应可通过随机访问迭代器访问并支持以下操作:

  • empty()
  • size()
  • front()
  • push_back()
  • pop_back()

标准容器类 vector和 deque满足这些要求。默认情况下,如果未为特定容器指定容器类

priority_queue 类实例化,默认使用vector作为底层容器。

需要支持随机访问迭代器,以始终在内部保持堆结构。容器适配器通过自动调用算法函数(make_heap, push_heap,pop_heap )维持堆结构。

B、操作基本数据类型

void testthree() 
{
	cout << "偷懒版本" << "	";
	priority_queue<int> q1;//默认less排,出队重大到小
	q1.push(1);
	q1.push(99);
	q1.push(0);
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;
	cout << "完整版本 less" << "	";
	priority_queue<int, vector<int>, less<int>> king;
	king.push(1);
	king.push(2);
	king.push(88);
	king.push(0);
	while (!king.empty())
	{
		cout << king.top() << " ";
		king.pop();
	}
	cout << endl;
	cout << "完整版本  greater" << "	";
	priority_queue<int, vector<int>, greater<int>> kin;
	kin.push(1);
	kin.push(2);
	kin.push(88);
	kin.push(0);
	while (!kin.empty())
	{
		cout << kin.top() << " ";
		kin.pop();
	}
	cout << endl;
}

C、操作自定义类型

第一种是写运算符重载,不常用,第二种是自己写仿函数描述函数准则

在这里插入图片描述

class MM 
{
public:
	MM(string name=" ",int age=0):name(name),age(age){}
	void print() const { cout << name << "	" << age << endl; }
	bool operator<(const MM& object) const
	{
		return this->age < object.age;
	}
	string getName()const { return name; }
	int getAge()const { return age; }
protected:
	string name;
	int age;
};
struct cmpAgeless 
{
	bool operator()(const MM& one, const MM& two) 
	{
		return one.getAge() > two.getAge();
	}
};
void test4() 
{
	cout << "不常用方法:重载运算符" << endl;
	priority_queue<MM, vector<MM>, less<MM>> mm;
	mm.push(MM("貂蝉", 19));
	mm.push(MM("妲己", 20));
	mm.push(MM("狂铁", 22));
	while (!mm.empty())
	{
		mm.top().print();
		mm.pop();
	}
	cout << endl;
	cout << "写仿函数,自己定义函数准则" << endl;
	priority_queue<MM, vector<MM>, cmpAgeless> mm1;
	mm1.push(MM("貂蝉", 19));
	mm1.push(MM("妲己", 20));
	mm1.push(MM("狂铁", 22));
	while (!mm1.empty())
	{
		mm1.top().print();
		mm1.pop();
	}
	cout << endl;
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。