一、栈与队列理论基础
队列:先进先出
栈:先进后出
栈提供push和pop等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。不像是set或者map提供迭代器iterator来遍历所有元素
栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用那种容器来实现栈的功能)
所以STL(C++标准库)中栈往往不被归类为容器,而被归类为container adapter(容器适配器)。
二、232用栈实现队列![](https://img-blog.csdnimg.cn/direct/c9c8b1cb47364b6983eb8e38caea9b3c.png)
![](https://img-blog.csdnimg.cn/direct/bdb64a19f647466b80c478117de5a927.png)
这道题先要明白栈里自己自带的函数有push() pop() peek() ,这个一开始困惑了好久 我以为是无限调用自己定义的函数,之后陷入了循环,没有解决出来
然后要注意的问题是可不可以封装抽象一部分函数,供pop和peek一起使用呢
因为这两个函数的逻辑都是返回栈顶的元素
我们是要用栈来实现队列,所以对于栈来说肯定是要用两个栈,并且是先进栈,再出栈进入另一个栈,所以要创建两个栈对象,Stack<Integer> Stackin;Stack<Integer> Stackout;
在这里注意一下Stack<Integer>这是一个泛型类,所以只会接受引用类型作为参数,不是接受基本数据类型,而Integer是引用类型,int是基本数据类型,不能放在这里,只能放引用类型,Integer是int的包装,
在 Java 中,
String
是引用类型,不是基本类型。尽管String
在 Java 中使用非常广泛,但它实际上是一个类而不是原始数据类型。Java 中的原始数据类型是int
、char
、boolean
等,而String
是一个对象,它是 Java 中的一个类。
第一个函数是创建队列,那么就用栈引用指向栈对象 Stackin = new Stack<>();Stacakout = new Stack(); 第二个函数直接入队 也就是Stackin进栈即可,第三个函数弹出Stackout的栈顶元素也就是队列的最开始入队的元素,但是这里需要注意了,如果Stackout的栈里没有元素那么就要从Stackin的栈里出栈元素
所以这部分抽象出来 先判断一下Stackout栈里是不是空,如果不是空,直接返回弹就完事了;如果是空,那么就要while循环Stackin是不是空,如果他也不是空,就循环把Stackin的值弹到Stackout中
因为这个整个过程是看Stackout里有没有值,如果他的值用完了,就从Stackin中弹。而对于他的操作就是push(Stackin.pop())里的值
之后的一个empty函数是判断队列是否是空的,直接return Stackin.isEmpty() && Stackout.isEmpty()即可
代码如下:
class MyQueue {
Stack<Integer> Stackin;
Stack<Integer> Stackout;
public MyQueue() {
Stackin = new Stack<>();
Stackout = new Stack<>();
}
public void push(int x) {
Stackin.push(x);
}
public int pop() {
dumpStackin();
return Stackout.pop();
}
public int peek() {
dumpStackin();
return Stackout.peek();
}
public boolean empty() {
return Stackin.isEmpty() && Stackout.isEmpty();
}
private void dumpStackin(){
if(!Stackout.isEmpty())
return;
while(!Stackin.isEmpty()){
Stackout.push(Stackin.pop());
}
}
}
/**
* 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();
* boolean param_4 = obj.empty();
*/
三、225.用队列实现栈
这道题主要是直到队列里的常用函数其实就好做了,队列里通常有addFirst(),addLast(x),pollFirst(),pollLast(),peekFirst(),peekLast()这些函数
这里还需要注意一点,这里实例化队列对象的时候,只能是用实现了Deque接口的类来实例化,不能用Deque自己实例化,但是可以用接口类型创建变量 Deque<Integer> que1;而这里
Deque<Integer> que1;
这行代码是在声明一个名为que1
的变量,其类型是Deque
,这意味着它可以引用任何实现了Deque
接口的类的对象。在这种情况下,你可以将que1
引用具体实现了Deque
接口的类的对象,例如ArrayDeque
。
这道题只用了一个队列,就解决了,其他的操作都可以直接实现比如说创建栈的函数 直接就是实例化一个队列对象就好了 que1 = new ArrayDeque(); 用que1去引用这个对象
压栈的过程可以直接调用que1.addLast(x)
输出栈顶元素可以这样做:可以先把队列的数量减一,然后把栈顶元素之前的元素全部移到队尾,这个过程就是一个入队还有出队的过程,队尾入队,队头出队,即que1.addLast(que1.peekFirst());que1.pollFirst();
然后正好循环结束就会剩下最后一个元素,因为我预先减了一,出了循环直接弹出栈顶元素,然后返回int res = que1.pollFirst();return res;
之后返回栈顶元素的函数其实就是返回队尾元素return que1.peekLast();
判断空的函数就是队列是否为空return que1.isEmpty();
代码如下:
class MyStack {
Deque<Integer> que1;
public MyStack() {
que1 = new ArrayDeque<>();
}
public void push(int x) {
que1.addLast(x);
}
public int pop() {
int size = que1.size();
size--;
while(size-->0){
que1.addLast(que1.peekFirst());
que1.pollFirst();
}
int res = que1.pollFirst();
return res;
}
public int top() {
return que1.peekLast();
}
public boolean empty() {
return que1.isEmpty();
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/