232.用栈实现队列
- 自我尝试
- 思路: 用俩栈模拟队列是通过两个栈来实现的。一个定义为输入栈,一个为输出栈。
- push: 添加元素,即可直接添加到输入栈里。
- pop: 如果输出栈当前还有元素,直接pop操作就好。但是如果没有,就将所有输入栈元素,导出到输出栈里。随后输出栈一个pop操作。
- peak:同样的,输出栈为准,使用栈的peek方法。
- 代码
// java有 Stack<类> class MyQueue { //two stacks Stack<Integer> sIn = new Stack<>(); Stack<Integer> sOut = new Stack<>(); public MyQueue() { sIn = new Stack<>(); sOut = new Stack<>(); } public void push(int x) { //add element sIn.push(x); } public void transit(){ if(sOut.empty()){ while(!sIn.empty()){ sOut.push(sIn.pop()); } } } public int pop() { transit(); return sOut.pop(); } public int peek() { // return the element at the head of the queue transit(); return sOut.peek(); } public boolean empty() { // True when two stacks are both empty return sIn.empty()&&sOut.empty(); } }
- 收获:
- Stack<>类:此类基于vector类实现的。
- empty():复杂度O(1)
- peek():复杂度O(1)
- push():复杂度O(1),在内部需要调整大小时候可能为O(n)
- search(object o):实现从vector末尾向前搜,复杂度O(n)
- Vector类:
- Vector内部使用动态数组来存储数据,可动态增删容量
- 所有公共方法是同步的即线程安全
- 容量增长每次x2
- Stack<>类:此类基于vector类实现的。
- 思路: 用俩栈模拟队列是通过两个栈来实现的。一个定义为输入栈,一个为输出栈。
225. 用队列实现栈
- 自我尝试
- 思路: 两个queue,一个拷贝,一个储存相同的元素, queue里的顺序与要实现的stack相反。
- pop的话,通过size()方法,抓到最后一个元素,也就是top,赋值后,将copy queue里的元素再返回回去。
- top的话类似,声明一个中间变量不停的变换。最后直接输出。
- 代码
class MyStack { // 思路,一个queue先进去元素,然后 Queue<Integer> qMain; Queue<Integer> qCopy; public MyStack() { qMain = new LinkedList<>(); qCopy = new LinkedList<>(); } public void push(int x) { qMain.offer(x); } public int pop() { int size = qMain.size(); for(int i=0;i<size-1;i++){ qCopy.offer(qMain.poll()); } int result = qMain.poll(); while(!qCopy.isEmpty()){ qMain.offer(qCopy.poll()); } return result; } public int top() { int top=0; int size = qMain.size(); for(int i=0;i<size;i++){ top = qMain.poll(); qCopy.offer(top); } while(!qCopy.isEmpty()){ qMain.offer(qCopy.poll()); } return top; } public boolean empty() { return qMain.isEmpty(); } }
- 收获
- 泛型类与泛型接口
- Stack<E>:是一个泛型具体类。
- Queue<E>:是一个接口,Queue<Integer>是一个泛型实例接口。
- Arraylist与LinkedList关系
- 内部结构: Arraylist是连续的动态数组。当容量超过当前极限,将会重新分配一个更大的; Linkedlist则是双链表储存结构
- 性能:
- 访问:Arraylist是O(1),而linkedlist需要O(n),即遍历整个数组
- 添删:
- 中间
- Arraylist:O(n)
- LinkedList: O(n), 因为要遍历找到那个位置先
- 头:
- Arraylist:O(n)
- LinkedList:O(1)
- 尾:
- Arraylist: O(1) 不扩容的情况下
- LinkedList: O(1)
- 中间
- 使用场景:
- 如果经常在列表的开头/结尾操作的话,用linkedlist
- 当while/for里的i<a.size()时候要注意,尤其是循环里涉及对a里元素更改时候。
- 泛型类与泛型接口
- 思路: 两个queue,一个拷贝,一个储存相同的元素, queue里的顺序与要实现的stack相反。
- 范例代码
- 思路: 将qMain保持与stack一样的元素顺序。pop,peak等方法就十分便利。
- 代码
class MyStack { // 思路,一个queue先进去元素,然后 Queue<Integer> qMain; Queue<Integer> qCopy; public MyStack() { qMain = new LinkedList<>(); qCopy = new LinkedList<>(); } public void push(int x) { //如果main里有元素,先pop到qCopy里 while(!qMain.isEmpty()){ qCopy.offer(qMain.poll()); } //添加元素,这样它保证再队列头部 qMain.add(x); //将余下元素放进来 while(!qCopy.isEmpty()){ qMain.offer(qCopy.poll()); } } public int pop() { return qMain.poll(); } public int top() { return qMain.peek(); } public boolean empty() { return qMain.isEmpty(); } }
- 收获
- Queue<T>接口方法:
- poll():移除队列的头部元素,若为空返回null
- peek():检查头部元素,并不删除。
add(E e)
: 尝试将元素添加到队列。如果成功则返回 true。如果没有空间,则抛出IllegalStateException
。offer(E e)
: 尝试将元素添加到队列。如果成功则返回 true,如果没有空间则返回 false。
- 两种实现比较:
- 执行时间:
- 自我方法:push-> O(1), top->O(n), pop->O(n);
- 范例: push->O(n), top->O(1)[本质查询链表第一个元素], pop->O(1)[本质链表移除第一个元素];
- 空间:
- 大致相同
- 执行时间:
- Queue<T>接口方法: