栈和队列总结
1.栈
1.1概念和特性
栈是一种特殊的线性储存结构,栈只能从一端(栈顶)压入或弹出数据,而且无论是压入还是弹出数据,都遵循先进后出的原则,例如:
A B D C
要想从栈中弹出元素D,就只能先出C再出D,没办法直接访问和弹出元素。
1.2模拟实现(类+模板)
1.3栈的应用场景
浏览器回退机制:一般我们打开一个网页A,在A中又打开了网页B,我们可以在网页B点击返回按钮,回到网页A,这样的回退就是用了栈的数据结构特性。
括号匹配问题:
有效的括号
利用栈的特性,进一个括号就检查一次,匹配的出栈,不匹配直接返回false。
class Solution {
public:
bool isValid(string s) {
int len = s.length();
if(len==0)
{
return true;
}
if(len%2!=0)
{
return false;
}
unordered_map<char,char> map{
{')','('},
{'}','{'},
{']','['},
};
stack<char> stk;
for(char ch:s)
{
if(map.count(ch))
{
if(stk.empty()||stk.top()!=map[ch])
{
return false;
}
stk.pop();
}
else
{
stk.push(ch);
}
}
return stk.empty();
}
};
1.4栈数据结构与程序栈帧或参数压栈的栈有何区别
2.队列
2.1概念和特性
队列是一种两端开口,只允许先进先出的线性储存结构,就像生活中排队一样,后进来的只能等前面的走完了,才轮到自己。队列也不支持随机访问和随机删除。
2.2模拟实现(类+模板)
2.3队列的应用场景
1、生活中的排队
2、消息队列
3、阻塞队列
4、线程池
3.栈和队列的OJ题
3.1用栈实现队列
利用栈的先进后出特性,因为队列是先进先出的,我们只需构建两个栈,先向栈A压入数据,需要出队列元素时,逐个弹出栈A元素,再逐个压入栈B,弹出栈B顶部元素即可。
template <typename T> class CQueue
{
public:
CQueue();
~CQueue();
void appendTail(const T &node)
{
sta1.push(node);
}
void deleteHead()
{
if (sta2.size() <= 0)
{
while (sta1.size() > 0)
{
sta2.push(sta1.top());
sta1.pop();
}
}
if (sta2.size() == 0)
{
throw new exception("queue is empty");
}
sta2.pop();
}
private:
stack<T> sta1;
stack<T> sta2;
};
3.2用队列实现栈
用队列实现栈也是利用各自的特性,构建两个队列,将元素都进入队列A中,此时队列B为空,需要弹出栈元素时,依次将队列A中元素出队,再依次存入队列B中,直到队列A剩下一个元素,将这个元素删除即可。
template<typename T> class CStack
{
public:
void append(const T &node)
{
if (que1.size() <= 0 && que2.size() > 0)
{
que2.push(node);
}
else
{
que1.push(node);
}
}
void deteleStack()
{
if (que1.size() <= 0 && que2.size() > 0)
{
while (que2.size() > 1)
{
que1.push(que2.front());
que2.pop();
}
que2.pop();
}
if (que2.size() <= 0 && que1.size()>0)
{
while (que1.size() > 1)
{
que2.push(que1.front());
que1.pop();
}
que1.pop();
}
if (que2.size() <= 0 && que1.size() <= 0)
{
throw new exception("stack is empty");
}
}
private:
queue<int> que1;
queue<int>que2;
};