面试的时候,栈和队列常常会成对出现来考察。本文包含栈和队列的以下考试内容:java
(1)栈的建立node
(2)队列的建立面试
(3)两个栈实现一个队列数组
(4)两个队列实现一个栈微信
(5)设计含最小函数min()的栈,要求min、push、pop、的时间复杂度都是O(1)函数
(6)判断栈的push和pop序列是否一致this
咱们接下来经过链表的形式来建立栈,方便扩充。设计
代码实现:3d
1 public class Stack { 2 3 public Node head; 4 public Node current; 5 6 7 //方法:入栈操做 8 public void push(int data) { 9 if (head == null) { 10 head = new Node(data); 11 current = head; 12 } else { 13 Node node = new Node(data); 14 node.pre = current;//current结点将做为当前结点的前驱结点 15 current = node; //让current结点永远指向新添加的那个结点 16 } 17 } 18 19 public Node pop() { 20 if (current == null) { 21 return null; 22 } 23 24 Node node = current; // current结点是咱们要出栈的结点 25 current = current.pre; //每出栈一个结点后,current后退一位 26 return node; 27 28 } 29 30 31 class Node { 32 int data; 33 Node pre; //咱们须要知道当前结点的前一个结点 34 35 public Node(int data) { 36 this.data = data; 37 } 38 } 39 40 41 public static void main(String[] args) { 42 43 Stack stack = new Stack(); 44 stack.push(1); 45 stack.push(2); 46 stack.push(3); 47 48 System.out.println(stack.pop().data); 49 System.out.println(stack.pop().data); 50 System.out.println(stack.pop().data); 51 } 52 53 }
入栈操做时,1四、15行代码是关键。指针
运行效果:
队列的建立有两种形式:基于数组结构实现(顺序队列)、基于链表结构实现(链式队列)。
咱们接下来经过链表的形式来建立队列,这样的话,队列在扩充时会比较方便。队列在出队时,从头结点head开始。
代码实现:
入栈时,和在普通的链表中添加结点的操做是同样的;出队时,出的永远都是head结点。
1 public class Queue { 2 public Node head; 3 public Node curent; 4 5 //方法:链表中添加结点 6 public void add(int data) { 7 if (head == null) { 8 head = new Node(data); 9 curent = head; 10 } else { 11 curent.next = new Node(data); 12 curent = curent.next; 13 } 14 } 15 16 //方法:出队操做 17 public int pop() throws Exception { 18 if (head == null) { 19 throw new Exception("队列为空"); 20 } 21 22 Node node = head; //node结点就是咱们要出队的结点 23 head = head.next; //出队以后,head指针向下移 24 25 return node.data; 26 27 } 28 29 30 class Node { 31 int data; 32 Node next; 33 34 public Node(int data) { 35 this.data = data; 36 } 37 } 38 39 40 public static void main(String[] args) throws Exception { 41 Queue queue = new Queue(); 42 //入队操做 43 for (int i = 0; i < 5; i++) { 44 queue.add(i); 45 } 46 47 //出队操做 48 System.out.println(queue.pop()); 49 System.out.println(queue.pop()); 50 System.out.println(queue.pop()); 51 52 } 53 }
运行效果:
思路:
栈1用于存储元素,栈2用于弹出元素,负负得正。
用栈1负责来添加操做,用栈2来实现弹出操做;若是栈2里面有元素,直接弹出,没有元素,判断栈1,栈1没有元素,返回错误;栈1有元素,则将栈1里面的元素都弹到栈2,而后从栈2中弹出元素。
完整版代码实现:
1 import java.util.Stack; 6 public class Queue { 7 8 Stack<Integer> stack1 = new Stack<Integer>(); Stack<Integer> stack2 = new Stack<Integer>(); 10 /** 11 * 每次添加都往栈1里面添加 12 * @param node 待插入队列中元素 13 */ 14 public void push(int node){ 15 stack1.push(node); 16 } 17 18 /** 19 * 每次弹出都从栈2里面弹出 20 * @return */ public int pop(){ if(!stack2.isEmpty()) return stack2.pop(); if(stack1.isEmpty()) return -1; else{ while(!stack1.isEmpty()) stack2.push(stack1.pop()); return stack2.pop(); } } 37 public static void main(String[] args) throws Exception { 38 Queue queue = new Queue(); 39 queue.push(1); 40 queue.push(2); 41 queue.push(3); 42 43 System.out.println(queue.pop()); 44 45 queue.push(4); 46 47 System.out.println(queue.pop()); 48 System.out.println(queue.pop()); 49 System.out.println(queue.pop()); 50 51 } 52 53 }
运行效果:
思路:
将一、二、3依次入队列一, 而后最上面的3留在队列一,将下面的二、3入队列二,将3出队列一,此时队列一空了,而后把队列二中的全部数据入队列一;将最上面的2留在队列一,将下面的3入队列二。。。依次循环。
代码实现:
1 import java.util.ArrayDeque; 2 import java.util.Queue; 3 7 public class Stack { 8 Queue queue1 = new LinkedList(); Queue queue2 = new LinkedList(); 11 12 /** * 添加元素的时候向不为空的队列中添加元素 * @param node */ public void push(int node){ if(queue2.isEmpty()) queue1.add(node); if(queue1.isEmpty()) queue2.add(node); } /** * 删除元素的时候先将不为空的队列的前n-1个元素添加到另一个队列中,而后将第n个元素删除 * @return */ public int poll(){ int temp = -1; if(!queue2.isEmpty()){ while(!queue2.isEmpty()){ temp = (int) queue2.poll(); if(!queue2.isEmpty()) queue1.add(temp); } return temp; }else if(!queue1.isEmpty()){ while(!queue1.isEmpty()){ temp = (int) queue1.poll(); if(!queue1.isEmpty()) queue2.add(temp); } return temp; }else return -1; } 36 37 public static void main(String[] args) throws Exception { 38 Stack stack = new Stack(); 39 40 stack.push(1); 41 stack.push(2); 42 stack.push(3); 43 44 System.out.println(stack.pop()); 45 System.out.println(stack.pop()); 46 stack.push(4); 47 } 48 }
运行效果:
普通思路:
通常状况下,咱们可能会这么想:利用min变量,每次添加元素时,都和min元素做比较,这样的话,就能保证min存放的是最小值。可是这样的话,会存在一个问题:若是最小的元素出栈了,那怎么知道剩下的元素中哪一个是最小的元素呢?
改进思路:
这里须要加一个辅助栈,用空间换取时间。辅助栈中,栈顶永远保存着当前栈中最小的数值。具体是这样的:原栈中,每次添加一个新元素时,就和辅助栈的栈顶元素相比较,若是新元素小,就把新元素的值放到辅助栈和原栈中,若是新元素大,就把元素放到原栈中;出栈时,若是原栈跟辅助栈元素相同,都弹出,不然只弹出原栈栈顶元素
完整代码实现:
1 import java.util.Stack; 2 6 public class MinStack { 7 8 Stack stack = new Stack(); //定义用来存储数据的栈 Stack minStack = new Stack(); //定义用来存储最小数据的栈 /** * 添加数据,首先是往stack栈中添加 * 若是最小栈minStack为空,或者栈顶的元素比新添加的元素要大,则将新元素也要添加的辅助栈中 * @param node */ public void push(int node) { stack.push(node); if(minStack.isEmpty() || ((int)minStack.peek()) >= node){ minStack.push(node); } } /** * 若是stack空,直接返回 * 若是stack不为空,获得栈顶元素,同时将栈顶元素弹出 * 若是最小栈的栈顶元素与stack弹出的元素相等,那么最小栈也要将其弹出 */ public void pop() { if(stack.isEmpty()) return; int node = (int)stack.peek(); stack.pop(); if((int)minStack.peek() == node){ minStack.pop(); } } /** * 查看栈顶元素 * @return */ public int top() { return (int)stack.peek(); } /** * 查看栈的最小元素 * @return */ public int min() { return (int)minStack.peek(); } 40 public static void main(String[] args) throws Exception { 41 MinStack stack = new MinStack(); 42 stack.push(4); 43 stack.push(3); 44 stack.push(5); 45 46 System.out.println(stack.min()); 47 } 48 }
通俗一点讲:已知一组数据一、二、三、四、5依次进栈,那么它的出栈方式有不少种,请判断一下给出的出栈方式是不是正确的?
例如:
数据:
一、二、三、四、5
出栈1:
五、四、三、二、1(正确)
出栈2:
四、五、三、二、1(正确)
出栈3:
四、三、五、一、2(错误)
完整版代码:
1 import java.util.Stack; 2 3 /** 4 * Created by smyhvae on 2015/9/9. 5 */ 6 public class StackTest { 7 8 /** * 首先将特殊状况,边界状况进行排除掉 * 而后定义一个循环,开始遍历第一个数组,将遍历的每一个对象往stack里面添加, * 若是遇到栈不为空且stack顶元素与第二个数组对应位置相等的状况,就弹栈, * 同时第二个数组指针后移 * 最后判断栈是否为空 * @param pushA 入栈队列 * @param popA 出栈队列 * @return */ public boolean isPopOrder(int[] pushA, int[] popA){ if(pushA == null || popA == null || pushA.length == 0 || popA.length == 0 || pushA.length != popA.length) return false; if(pushA.length == popA.length && pushA.length == 1) return pushA[0] == popA[0]; Stack stack = new Stack(); int i = 0; int j = 0; int len = pushA.length; while(i < len && j < len){ stack.push(pushA[i]); ++i; while(!stack.isEmpty() && (int)stack.peek() == popA[j]) { stack.pop(); ++j; } } return stack.isEmpty(); } 24 25 public static void main(String[] args) { 26 27 Stack<Integer> stack = new Stack<Integer>(); 28 29 int[] data1 = {1, 2, 3, 4, 5}; 30 int[] data2 = {4, 5, 3, 2, 1}; 31 int[] data3 = {4, 5, 2, 3, 1}; 32 33 System.out.println(sequenseIsPop(data1, data2)); 34 System.out.println(sequenseIsPop(data1, data3)); 35 } 36 }
代码比较简洁,但也比较难理解,要仔细体会。
运行效果: