目录
一、受限线性表基本理论
(一)、栈
栈( s t a c k stack stack)是一种满足“先入后出”( L I F O LIFO LIFO)特性的受限线性表
栈在C++中可以使用 S T L STL STL 标准库中的 < s t a c k > <stack> <stack> 头文件进行构建,主要操作有:
stack.push(ElemType elem);//元素压栈
stack.pop();//元素弹出但不返回
stack.top();//栈顶元素返回但不弹出
stack.empty();//判断是否空栈
(二)、队列
队列( q u e u e queue queue)是一种满足“先入先出”( F I F O FIFO FIFO)的受限线性表
与栈类似,队列可使用 S T L STL STL 标准库中的 < q u e u e > <queue> <queue> 头文件进行构建,主要操作有:
queue.push(ElemType elem);//元素入队
queue.pop();//元素出队但不返回
queue.front();//返回队首元素
queue.empty();//判断队列是否为空
C++中还提供了双端队列
d
e
q
u
e
deque
deque ,可以实现队列两端的访问、压入元素、弹出元素操作。
二、LeetCode 232.用栈实现队列
题目链接:LeetCode 232.用栈实现队列
文章讲解:代码随想录
视频讲解:栈的基本操作! | LeetCode:232.用栈实现队列
思路:
基本思路为建立两个栈,用来互相倾倒元素调换顺序,当需要输出队头元素时,将主栈中的元素全部放入辅助栈中,再输出辅助栈中栈顶元素,即可达到先入先出的效果;具体功能实现依照题意编程即可
C++代码
class MyQueue {
private:
stack<int> queue;
stack<int> asst;
public:
MyQueue() {
}
void push(int x) {
while(!asst.empty()){
int elem = asst.top();
asst.pop();
queue.push(elem);
}
queue.push(x);
}
int pop() {
int elem = peek();
asst.pop();
return elem;
}
int peek() {
while(!queue.empty()){
int elem = queue.top();
queue.pop();
asst.push(elem);
}
return asst.top();
}
bool empty() {
if(queue.empty() && asst.empty()){
return true;
}
else{
return false;
}
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
三、LeetCode 225. 用队列实现栈
题目链接:添加链接描述
文章讲解:代码随想录
视频讲解:队列的基本操作! | LeetCode:225. 用队列实现栈
思路
由于队列两端开口,所以本题仅需要一个队列即可完成;当需要输出栈顶元素时,将队列前段所有元素取出再放入队尾即可;
C++代码
class MyStack {
public:
queue<int> que;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
que.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int size = que.size();
size--;
while (size--) { // 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部
que.push(que.front());
que.pop();
}
int result = que.front(); // 此时弹出的元素顺序就是栈的顺序了
que.pop();
return result;
}
/** Get the top element.
** Can not use back() direactly.
*/
int top(){
int size = que.size();
size--;
while (size--){
// 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部
que.push(que.front());
que.pop();
}
int result = que.front(); // 此时获得的元素就是栈顶的元素了
que.push(que.front()); // 将获取完的元素也重新添加到队列尾部,保证数据结构没有变化
que.pop();
return result;
}
/** Returns whether the stack is empty. */
bool empty() {
return que.empty();
}
};
四、LeetCode 20. 有效的括号
题目链接:LeetCode 20. 有效的括号
文章讲解:代码随想录
视频讲解:栈的拿手好戏!| LeetCode:20. 有效的括号
思路
这其实是学校学习数据结构时的一道作业题,所以从善如流;
括号匹配十分适合使用栈进行操作,具体实现思路为:遇到左括号则入栈,遇到右括号时,访问栈顶元素,看是否是和当前匹配的左括号,匹配则左括号出栈,不匹配则返回false
.
C++代码
class Solution {
public:
bool isValid(string s) {
stack<char> match;
for(auto x: s){
if(x == ')'){
if(!match.empty() && match.top() == '('){
match.pop();
continue;
}
}
else if(x == ']'){
if(!match.empty() && match.top() == '['){
match.pop();
continue;
}
}
else if(x == '}'){
if(!match.empty() && match.top() == '{'){
match.pop();
continue;
}
}
match.push(x);
}
if(match.empty()){
return true;
}
else{
return false;
}
}
};
以上代码是对所有括号操作以后查询栈是否为空,在此基础上可以做一定剪枝,即右括号不匹配直接返回false
;
五、LeetCode 1047. 删除字符串中的所有相邻重复项
题目链接:LeetCode 1047. 删除字符串中的所有相邻重复项
思路
这道题的思想和上一题括号匹配有些类似。在栈的生成部分,碰到匹配项出栈,否则入栈或执行其他操作;最后栈中剩下的元素重新输入到字符串中,而由于栈是逆序输出的,因此在末尾需要对字符串进行一次反转,得到需要的结果。
C++代码
class Solution {
public:
string removeDuplicates(string s) {
stack<char> nonrep;
for(char x: s){
if(!nonrep.empty() && x == nonrep.top()){
nonrep.pop();
continue;
}
nonrep.push(x);
}
s.clear();
while(!nonrep.empty()){
char x = nonrep.top();
nonrep.pop();
s.push_back(x);
}
reverse(s.begin(), s.end());
return s;
}
};
总结
栈与队列是基础的数据结构之一,打好数据结构的应用基础很重要。
文章图片来源:代码随想录 (https://programmercarl.com/)