stack的介绍和使用
stack的介绍
- stack是一种容器适配器(半封闭式的容器),专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
- stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
- stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:
- empty:判空操作
- back:获取尾部元素操作
- push_back:尾部插入元素操作
- pop_back:尾部删除元素操作
stack的使用
函数说明接口说明
stack() :构造空的栈
empty() :检测stack是否为空
size() :返回stack中元素的个数
top() :返回栈顶元素的引用
push(): 将元素val压入stack中
pop() :将stack中尾部的元素弹出
代码示例:
void test()
{
stack<int> st;
st.push(1);
st.push(2);
st.push(3);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
cout << st.size() << endl;
}
最小栈理解:
当需要找出栈内元素最小值时,需要对栈进行遍历操作,时间复杂度为O(n)。并且如果对栈内元素再进行修改后(例如对一些元素进行出栈,可能把最小值出掉),需要重新遍历。
鉴于前面的时间复杂度过高,因此最小栈的思路为:
同时定义两个栈,另一个栈用来记录最小值(最小栈)。
1.在将数据进行压栈操作时,第一个元素两个栈都进行压入。
2.第二个元素开始不同,将第二个元素和最小栈中的栈顶元素进行比较,小于等于则压入,大于栈顶元素则不进行压入。
3.在对栈内元素进行出栈操作时,需要将该元素和最小栈栈顶元素进行比较,如果相等,也同时将最小栈的栈顶元素进行出栈。
这样的话当对栈内元素进行修改时,保证栈内一直存在最小值。
class MinStack
{
public:
void push(int val)
{
_st.push(val);
if (_minSt.empty() || val <= _minSt.top())
_minSt.push(val);
}
void pop()
{
if (_minSt.top() == _st.top())
_minSt.pop();
_st.pop();
}
int top()
{
return _st.top();
}
int getMin()
{
return _minSt.top();
}
private:
//保存栈内元素
stack<int> _st;
//保存栈内最小元素
stack<int> _minSt;
};
栈的弹出压入序列
//栈的弹出压入序列
class Solution
{
public:
bool IsPopOrder(vector<int> pushV, vector<int> popV)
{
//用st来模拟入栈、出栈过程
stack<int> st;
int pushIdx = 0;
int popIdx = 0;
while (pushIdx < pushV.size())
{
//每次入栈一个元素
st.push(pushV[pushIdx++]);
//循环判断当前栈顶元素是否是需要出栈的元素
while (!st.empty() && st.top() == popV[popIdx])
{
st.pop();
popIdx++;
}
}
return st.empty();
}
};
stack的实现
1.顺序表:
push(入栈):push_back 尾插(效率最高为O(1),头插的话效率是O(n))
pop(入栈):pop_back 尾插
top:back获取最后一个元素
//用vector实现栈
template <class T>
class Stack
{
public:
void push(const T& val)
{
_st.push_back(val);
}
void pop()
{
_st.pop_back();
}
T& top()
{
return _st.back();
}
size_t size() const
{
return _st.size();
}
bool empty() const
{
reutrn _st.empty();
}
private:
vector<T> _st;
};
void test()
{
Stack<int> st;
st.push(1);
st.push(2);
st.push(3);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
cout << st.size() << endl;
}
2.链表(单链表):
push(入栈):push_front 头插(效率最高为O(1),尾插需要从头遍历一遍效率是O(n))
pop(出栈):pop_front 头删
top:获取第一个节点的值
代码给出示例使用的是双向循环链表(头插尾插效率都是O(1)):
//用list实现栈:更加灵活,因为list是一个双向带头循环链表
template <class T>
class Stack2
{
public:
void push(const T& val)
{
//头插尾插都是O(1)操作 但是如果选择其中一种操作的话,后面也都要选择该侧(头或者尾)
_st.push_front(val);
//_st.push_back(val);
}
void pop()
{
_st.pop_front();
//_st.pop_back();
}
T& top()
{
return _st.front();
//return _st.back();
}
size_t size() const
{
return _st.size();
}
bool empty() const
{
reutrn _st.empty();
}
private:
list<T> _st;
};