栈应用举例
栈是操作受限的线性表,典型生活中的用例:压入子弹。std::stack
类是一种容器适配器,它给予程序员栈的功能,特别是 FILO(先进后出)数据结构。该类模板用处为底层容器的包装器,只提供特定函数集合。栈从被称作栈顶的容器尾部推弹元素。
C++ stack的基本操作 | ||
s.pop() | 修改器 | 删除栈顶元素,但不返回该元素的值 |
swap() | ||
s.push(item) | 创建一个新元素压入栈顶,该元素通过拷贝或移动item而来,或者由args构造 | |
s.emplace(args) | ||
s.top() | 元素访问 | 返回栈顶元素,但是不将元素弹出栈 |
empty()、size() | 容量 | empty检查容器是否为空,size返回元素数 |
栈默认基于deque实现,也可以在list或vector之上实现 |
std::stack的基本操作:
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<int> s;
// push() 压入元素
s.push(1);
s.push(2);
s.push(3);
//容量
cout << "s.size() = " << s.size() << endl;
cout << "s.empty() = " << s.empty() << endl;
if (!s.empty())
cout << "栈顶元素s.top() = " << s.top() << endl;
//元素访问
s.pop(); // 弹出栈顶元素
cout << "s.size() = " << s.size() << " s.empty() = " << s.empty() << endl;
if (!s.empty())
cout << "s.top() = " << s.top() << endl;
//推入新元素到 stack 顶。原位构造元素,即不进行移动或复制操作
s.emplace(3);
stack<int> s1;//空栈
s1.swap(s); // s和s1进行交换
cout << "s.size() = " << s.size() << " s.empty() = " << s.empty() << endl;
if (!s.empty())
cout << "栈顶元素,即s.top() = " << s.top() << endl;
else
cout << "栈空不能使用top访问栈顶元素" << endl;
cout << "s1.size() = " << s1.size() << " s1.empty() = " << s1.empty() << endl;
if (!s1.empty())
cout << "栈顶元素,即s1.top() = " << s1.top() << endl;
return 0;
}
应用实例(一):括号匹配
输入给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效
bool isValid(string s) {
stack<char> sta;
if (s.size() % 2 == 1) {
return false;
}
for (auto ch : s) {
if (sta.empty() || ch == '{' || ch == '[' || ch == '(') {
sta.push(ch);
} else if (ch == ']' && !sta.empty() && sta.top() == '[')
sta.pop();
else if (ch == '}' && !sta.empty() && sta.top() == '{')
sta.pop();
else if (ch == ')' && !sta.empty() && sta.top() == '(')
sta.pop();
else
sta.push(ch);
}
return sta.empty();
}
非栈方式
bool isValid(string s) {
int len=s.length()/2;
std::string::size_type n;
for(int i=0;i<len;i++){
n=s.find("()");
if(n != std::string::npos){
s.replace(s.find("()"),2,"");
}
n=s.find("{}");
if(n != std::string::npos){
s.replace(s.find("{}"),2,"");
}
n=s.find("[]");
if(n != std::string::npos){
//cout<<f;
s.replace(s.find("[]"),2,"");
}
}
return s.empty();
}
队列的应用
队:
一种先进先出的数据结构,std::queue也是一种容器适配器,遵循先进先出FIFO原则,其中从容器一端插入元素,另一端提取元素。
priority_queue是C++标准库中的一个容器适配器,用于实现优先队列的数据结构。优先队列是一种特殊的队列,其中的元素按照一定的优先级进行排序,每次取出的元素都是优先级最高的。它的底层实现通常使用堆(heap)数据结构。它提供常数时间的(默认)最大元素查找,对数代价的插入与提取。可以通过用户提供的 Compare
更改顺序,例如,用 std::greater<T> 将导致最小元素作为top()出现。默认使用std::less比较使得最大元素出现在堆顶。priority_queue
的作用类似于管理某些随机访问容器中的堆,其优势是不可能意外使堆失效。
C++的队列适配器queue和priority_queue适配器定义在queue头文件中,queue默认基于deque实现,也可以用list或vector实现,priority_queue默认基于vector实现,也可以用deque实现 | |
q.pop() | 移除quene的首元素或priority_queue的最高优先级的元素 |
q.front() | 返回首元素或尾元素,但是不删除此元素,q.back只适用于quene |
q.back() | |
q.top() | 返回最高优先级元素不删除该元素只适用于priority_queue |
q.push(item) | 在queue末尾或priority_queue中恰当位置创建一个值为item的元素或者由args构造 |
q.emplace(args) |
std::queue 基本操作
#include <iostream>
#include<queue>
using namespace std;
int main()
{
queue<int> q; //默认使用 deque
//queue<double, vector<double>> qVector; //指定使用 vector
q.push(1);
q.push(2);
q.push(3);
cout << q.size() << endl; //元素个数 size() 3
cout << q.front() << endl; //队头元素 front() 1
cout << q.back() << endl; //队尾元素 队尾元素back() 3
q.pop(); // 出队pop()
cout << q.size() << endl; //2
cout << q.front() << endl; //2
while (!q.empty()) //判空 empty()
{
cout << q.front() << " "; //2 3
q.pop();
}
cout << q.size() << endl; //0
queue<int> q1;
q1.push(4);
q1.push(5);
q1.push(6);
cout <<"before swap q size is "<< q.size() <<" before swap q1 size is "<<q1.size()<< endl; //0 3
q.swap(q1); //交换
cout <<"after swap q size is "<< q.size() <<" after swap q1 size is "<<q1.size()<< endl; //3 0
priority_queue<int> pq; //直接构造一个空对象,默认为大堆
priority_queue<int, std::vector<int>, std::greater<int>> pq1; // 构建小堆
cout<<"----------priority_queue----"<<endl;
pq.push(1);
pq.push(2);
pq.push(3);
cout<<pq.size()<<" "<<pq.empty()<<endl; //3 0判空empty 元素数 size
cout << pq.top() << endl; //优先级最高的元素 3
pq1.push(1);
pq1.push(2);
pq1.push(3);
cout<<pq1.size()<<" "<<pq1.empty()<<endl; //3 0判空empty 元素数 size
cout << pq1.top() << endl; // 1
pq1.pop();
cout<<pq1.size()<<" "<<pq1.empty()<<endl; //2 0判空empty 元素数 size
priority_queue<int> pq2; //直接构造一个空对象,默认为大堆
cout<<pq2.size()<<" "<<pq2.empty()<<endl; //0 1判空empty 元素数 size
pq.swap(pq2); //交换的前提必须是 两个队列构建都是相同的类型的堆
cout<<pq.size()<<" "<<pq.empty()<<endl; //0 1判空empty 元素数 size
cout<<pq2.size()<<" "<<pq2.empty()<<endl; //3 0判空empty 元素数 size
return 0;
}
队列应用举例:
1、约瑟夫问题
:N个人围成一圈,从第一个人开始报数,数到M的人出圈;再由下一个人开始报数,数到M的人出圈
数组实现:
#include <string>
#include <iostream>
using namespace std;
int main(){
int n,m,flag=0;
cin>>n>>m;
int count=0,len=1,arr[n+1]={0};
for(int i=1;i<=n;i++){
arr[i]=i;
}
while(flag!=n)//一共n个人
{
if(arr[len]!=0){//如果数组不为0,就计数已经输出的人将其值赋值为了0
count++;
}
if(count==m)//计数值为m输出该点的值并将其赋值为0
{
count=0;
cout<<arr[len]<<" ";
arr[len]=0;
flag++;//记录已经输出个数
}
len=(len+1)%(n+1);//循环一次len++
}
return 0;
}
队列实现:
#include <bits/stdc++.h>
using namespace std;
int main()
{
queue<int> que;
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
que.push(i);
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m - 1; ++j)
{//将队头的人出队后,再入队到队尾
que.push(que.front());
que.pop();
}
cout << que.front() << ' ';//此时队头是要出列的人
que.pop();
}
return 0;
}
双向链表
#include<bits/stdc++.h>
using namespace std;
int main()
{
list<int> li;
int n, m, ct = 0;
cin >> n >> m;
for(int i = 1; i <= n; ++i)
li.push_back(i);
list<int>::iterator it = li.begin();
while(li.empty() == false)
{
ct++;
if(ct == m)
{
cout << *it << ' ';
it = li.erase(it);
ct = 0;
}
else
it++;
if(it == li.end())
it = li.begin();
}
return 0;
}