棧和隊列的面試題Java實現【重要】


 

棧和隊列: 

面試的時候,棧和隊列經常會成對出現來考察。本文包含棧和隊列的如下考試內容:

  (1)棧的創建

  (2)隊列的創建

  (3)兩個棧實現一個隊列

  (4)兩個隊列實現一個棧

  (5)設計含最小函數min()的棧,要求min、push、pop、的時間復雜度都是O(1)

  (6)判斷棧的push和pop序列是否一致

 

1、棧的創建:

    我們接下來通過鏈表的形式來創建棧,方便擴充。

代碼實現:

 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 }

入棧操作時,14、15行代碼是關鍵。

運行效果:

e6e0ae76-0eed-4f1c-95a0-10e543237d63

  

2、隊列的創建:

  隊列的創建有兩種形式:基於數組結構實現(順序隊列)、基於鏈表結構實現(鏈式隊列)。

  我們接下來通過鏈表的形式來創建隊列,這樣的話,隊列在擴充時會比較方便。隊列在出隊時,從頭結點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 }

運行效果:

fd770486-0cbe-45d8-96a7-0f3116045a35

  

3、兩個棧實現一個隊列:

思路:

    棧1用於存儲元素,棧2用於彈出元素,負負得正

    說的通俗一點,現在把數據1、2、3分別入棧一,然后從棧一中出來(3、2、1),放到棧二中,那么,從棧二中出來的數據(1、2、3)就符合隊列的規律了,即負負得正。

完整版代碼實現:

 1 import java.util.Stack;
 2 
 3 /**
 4  * Created by smyhvae on 2015/9/9.
 5  */
 6 public class Queue {
 7 
 8     private Stack<Integer> stack1 = new Stack<>();//執行入隊操作的棧
 9     private Stack<Integer> stack2 = new Stack<>();//執行出隊操作的棧
10 
11 
12     //方法:給隊列增加一個入隊的操作
13     public void push(int data) {
14         stack1.push(data);
15 
16     }
17 
18     //方法:給隊列正價一個出隊的操作
19     public int pop() throws Exception {
20 
21 
22         if (stack2.empty()) {//stack1中的數據放到stack2之前,先要保證stack2里面是空的(要么一開始就是空的,要么是stack2中的數據出完了),不然出隊的順序會亂的,這一點很容易忘
23 
24             while (!stack1.empty()) {
25                 stack2.push(stack1.pop());//把stack1中的數據出棧,放到stack2中【核心代碼】
26             }
27 
28         }
29 
30         if (stack2.empty()) { //stack2為空時,有兩種可能:1、一開始,兩個棧的數據都是空的;2、stack2中的數據出完了
31             throw new Exception("隊列為空");
32         }
33 
34         return stack2.pop();
35     }
36 
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 }

注意第22行和第30行代碼的順序,以及注釋,需要仔細理解其含義。

運行效果:

e5334faf-a36e-4aa2-9fe3-18157717bacd

  

4、兩個隊列實現一個棧:

思路:

  將1、2、3依次入隊列一, 然后最上面的3留在隊列一,將下面的2、3入隊列二,將3出隊列一,此時隊列一空了,然后把隊列二中的所有數據入隊列一;將最上面的2留在隊列一,將下面的3入隊列二。。。依次循環。

代碼實現:

 1 import java.util.ArrayDeque;
 2 import java.util.Queue;
 3 
 4 /**
 5  * Created by smyhvae on 2015/9/9.
 6  */
 7 public class Stack {
 8 
 9     Queue<Integer> queue1 = new ArrayDeque<Integer>();
10     Queue<Integer> queue2 = new ArrayDeque<Integer>();
11 
12     //方法:入棧操作
13     public void push(int data) {
14         queue1.add(data);
15     }
16 
17     //方法:出棧操作
18     public int pop() throws Exception {
19         int data;
20         if (queue1.size() == 0) {
21             throw new Exception("棧為空");
22         }
23 
24         while (queue1.size() != 0) {
25             if (queue1.size() == 1) {
26                 data = queue1.poll();
27                 while (queue2.size() != 0) {  //把queue2中的全部數據放到隊列一中
28                     queue1.add(queue2.poll());
29                     return data;
30                 }
31             }
32             queue2.add(queue1.poll());
33         }
34         throw new Exception("棧為空");//不知道這一行的代碼是什么意思
35     }
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 }

運行效果:

7c0470f9-0558-4b00-9e04-51d018dd6081

  

5、設計含最小函數min()的棧,要求min、push、pop、的時間復雜度都是O(1)。min方法的作用是:就能返回是棧中的最小值。【微信面試題】

普通思路:

  一般情況下,我們可能會這么想:利用min變量,每次添加元素時,都和min元素作比較,這樣的話,就能保證min存放的是最小值。但是這樣的話,會存在一個問題:如果最小的元素出棧了,那怎么知道剩下的元素中哪個是最小的元素呢?

改進思路:

    這里需要加一個輔助棧,用空間換取時間。輔助棧中,棧頂永遠保存着當前棧中最小的數值。具體是這樣的:原棧中,每次添加一個新元素時,就和輔助棧的棧頂元素相比較,如果新元素小,就把新元素的值放到輔助棧中,如果新元素大,就把輔助棧的棧頂元素再copy一遍放到輔助棧的棧頂;原棧中,出棧時,

完整代碼實現:

 1 import java.util.Stack;
 2 
 3 /**
 4  * Created by smyhvae on 2015/9/9.
 5  */
 6 public class MinStack {
 7 
 8     private Stack<Integer> stack = new Stack<Integer>();
 9     private Stack<Integer> minStack = new Stack<Integer>(); //輔助棧:棧頂永遠保存stack中當前的最小的元素
10 
11 
12     public void push(int data) {
13         stack.push(data);  //直接往棧中添加數據
14 
15         //在輔助棧中需要做判斷
16         if (minStack.size() == 0 || data < minStack.peek()) { 17  minStack.push(data); 18         } else { 19             minStack.add(minStack.peek());   //【核心代碼】peek方法返回的是棧頂的元素
20  } 21     }
22 
23     public int pop() throws Exception {
24         if (stack.size() == 0) {
25             throw new Exception("棧中為空");
26         }
27 
28         int data = stack.pop();
29         minStack.pop();  //核心代碼
30         return data;
31     }
32 
33     public int min() throws Exception {
34         if (minStack.size() == 0) {
35             throw new Exception("棧中空了");
36         }
37         return minStack.peek();
38     }
39 
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 }

604a9d9a-6e44-4cdf-ab4a-da3070e39ea1

  

6、判斷棧的push和pop序列是否一致:

    通俗一點講:已知一組數據1、2、3、4、5依次進棧,那么它的出棧方式有很多種,請判斷一下給出的出棧方式是否是正確的?

例如:

數據:

  1、2、3、4、5

出棧1:

  5、4、3、2、1(正確)

出棧2:

  4、5、3、2、1(正確)

出棧3:

  4、3、5、1、2(錯誤)

完整版代碼:

 1 import java.util.Stack;
 2 
 3 /**
 4  * Created by smyhvae on 2015/9/9.
 5  */
 6 public class StackTest {
 7 
 8 
 9     //方法:data1數組的順序表示入棧的順序。現在判斷data2的這種出棧順序是否正確
10     public static boolean sequenseIsPop(int[] data1, int[] data2) {
11         Stack<Integer> stack = new Stack<Integer>(); //這里需要用到輔助棧
12 
13         for (int i = 0, j = 0; i < data1.length; i++) {
14             stack.push(data1[i]);
15 
16             while (stack.size() > 0 && stack.peek() == data2[j]) { 17  stack.pop(); 18                 j++; 19  } 20         }
21         return stack.size() == 0; 22     }
23 
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 }

代碼比較簡潔,但也比較難理解,要仔細體會。

運行效果:

1cca8bbf-0eee-4049-88b6-d10a4f8c838a

 

我的公眾號

下圖是我的微信公眾號(生命團隊id:vitateam),歡迎有心人關注。博客園分享技術,公眾號分享心智

我會很感激第一批關注我的人。此時,年輕的我和你,一無所有;而后,富裕的你和我,滿載而歸。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM