0%

C++ 資料結構 Stack & Queue

Stack,又稱作堆疊,顧名思義就是從上面(也可以說前面)放入與取出的資料結構。 Queue,稱為佇列,是從前面放後面取出的資料結構。

實作程式碼如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include<bits/stdc++.h>
using namespace std;

template<class T>
class Stack{
private:
int t=-1;
vector<T> dt;
public:
T top(){
if(t!=-1){
return dt[t];
}else{
cout<<"Stack is empty.\n";
}
}

void pop(){
if(t!=-1){
t--;
dt.pop_back();
}else{
cout<<"Stack is empty.\n";
}
}

void push(T p){
t++;
dt.push_back(p);
}
};

template<class T>
class Queue{
private:
deque<T> dt;
public:
T front(){
if(!dt.empty()){
return dt.front();
}else{
cout<<"Queue is empty.\n";
}
}

void pop(){
if(!dt.empty()){
dt.pop_front();
}else{
cout<<"Queue is empty.\n";
}
}

void push(T p){
dt.push_back(p);
}
};

C++已經幫你將這兩個資料結構實做好了,以下示範例程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<stack>
#include<queue>
#include<deque>

using namespace std;

int main(){
stack<int> st;
for(int i=0;i<10;++i){
st.push(i);
}
cout<<st.size()<<"\n";
while(!st.empty()){
cout<<st.top()<<" ";
st.pop();
}
cout<<"\n\n";

queue<int> q;
for(int i=0;i<10;++i){
q.push(i);
}
cout<<q.size()<<"\n";
while(!q.empty()){
cout<<q.front()<<" "<<q.back()<<"\n";
q.pop();
}
cout<<"\n";
}

光聽這兩個介紹以及大部分的分享,相信你還是不知道這兩個東西要用在哪裡。以下會有幾個應用的範例,都是用 STL 。

1.在 O(N) 的複雜度下做單調對列 Ex : 洛谷

題目敘述: 對於每個元素,從後面找出第一個比他大的元素的位置

這題就是要透過 stack 保持裡面所存位置對應的元素的單調遞減性。實際做法就是,遇到比他大的就丟掉,反正已經確認現在這個元素已經比他大了,後面也不會用到。否則他就還沒遇到還沒遇到比他大的。

以下為程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<bits/stdc++.h>
using namespace std;

int main(){
ios::sync_with_stdio(0);cin.tie(0);

int n;
cin>>n;
vector<int> v(n);
for(int i=0;i<n;++i) cin>>v[i];

vector<int> ans(n,0);
stack<int,vector<int>> st;
for(int i=0;i<n;++i){
while(!st.empty() && v[st.top()]<v[i]){
ans[st.top()]=i+1;
st.pop();
}
st.push(i);
}

for(int a:ans)
cout<<a<<" ";
}

2.以 O(N) 在滑動窗口中找最大以及最小值 Ex : 洛谷

題目敘述: 在所有長度為k的窗口中找到最大以及最小值

這題要用deque(double-ended-queue),也就是雙向佇列,是一個從前後方都可以加入以及刪除值的queue。用以維持內部元素既在範圍以內,又保持單調遞增或遞減。

以下為程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<bits/stdc++.h>
using namespace std;
#define ll long long

int nm[1000010]={0},rmax[1000010],rmin[1000010];

int main(){
int n,k;
cin>>n>>k;

for(int i=0;i<n;i++) cin>>nm[i];

deque<int> mx,mn;

for(int i=0;i<k;i++){
while(!mx.empty() && nm[mx.front()]<nm[i])
mx.pop_front();
mx.push_front(i);

while(!mn.empty() && nm[mn.front()]>nm[i])
mn.pop_front();
mn.push_front(i);
}

rmax[0]=mx.back();
rmin[0]=mn.back();

for(int i=1,j=k;j<n;i++){

while(!mx.empty() && mx.back()<i)
mx.pop_back();
while(!mn.empty() && mn.back()<i)
mn.pop_back();

while(!mx.empty() && nm[mx.front()]<nm[j])
mx.pop_front();
mx.push_front(j);
while(!mn.empty() && nm[mn.front()]>nm[j])
mn.pop_front();
mn.push_front(j);

rmax[i]=mx.back();
rmin[i]=mn.back();

j++;
}

for(int i=0;i<n-k+1;i++)
cout<<nm[rmin[i]]<<" ";
cout<<"\n";
for(int i=0;i<n-k+1;i++)
cout<<nm[rmax[i]]<<" ";
return 0;
}