演算法:棧和佇列題目集合(一)
阿新 • • 發佈:2020-01-03
前言
棧和佇列是演算法的一個基本的知識點之一。這篇文章主要介紹三道有關棧和佇列的演算法題。因為篇幅所限,只介紹push和pop這兩種方法的實現- 用棧實現佇列
- 用佇列實現棧
- 迴圈佇列的實現
用棧實現佇列
入佇列的功能我們可以用棧的入棧的功能替代。但問題在於出佇列的功能怎麼實現。 這裡有一個問題,就是棧是後入先出的,佇列是先進先出的,兩者出入的方式不一樣。 那麼怎麼實現方向的一致呢? 我們可以使用兩個棧,一個棧用於輸入,一個棧用於輸出。當發現輸出棧為空的時候,把排列的資料從輸入棧一個個彈出,“倒入”到 輸出棧中,這樣的話,資料排列的方向就剛好被逆轉過來了,原本在輸入棧中處於棧底的資料被置換到輸出棧的棧頂,這時候對它出棧也就同時完成了佇列的出列的功能。 下面是具體的圖示 1.入佇列操作: 等同於對入佇列進行入棧操作,圖示如下 2.出佇列操作: 判斷當輸出棧為空時,先把輸入棧的資料依次彈出並加入到輸出棧中 步驟1 步驟2 對輸出棧棧頂進行出棧操作,即可完成出佇列功能 步驟3 具體程式碼import java.util.Stack; class MyQueue { private Stack<Integer> stack1; private Stack<Integer> stack2; private boolean isPushState = true; /** Initialize your data structure here. */ public MyQueue() { // 輸入棧 stack1 = new Stack<Integer>(); // 輸出棧 stack2 = new Stack<Integer>(); } /** Push element x to the back of queue. */ public void push(int x) { stack1.push(x); } public void transformStack () { if (stack2.empty()) { while (!stack1.empty()) { int t = stack1.pop(); stack2.push(t); } } } /** Removes the element from in front of queue and returns that element. */ public int pop() { transformStack(); return stack2.pop(); } /** Returns whether the queue is empty. */ public boolean empty() { return stack1.empty() && stack2.empty(); } }
用佇列實現棧
這裡同樣有兩個功能需要我們實現,分別是入棧功能和出棧功能 入棧功能 我們可以用入棧操作模擬實現 出棧功能 我們又來到了關鍵功能,這時候你能猜到,我們又需要用到兩個佇列去實現這個出棧功能了 但問題在於,我們還能否通過講資料從一個佇列“倒”到另一個佇列的方式逆轉資料方向呢? 這是不行的,因為佇列先入先出的特性,導致分割後佇列的出入方向仍然是不變的。所以我們要換個思路: 一個元素入隊列了,我們接下來希望這個佇列像棧一樣通過pop把它直接彈出來,但是前面還有很多個元素排著隊呢,這時我們想,只要把前面排隊的所有元素先出列到另外一個輔助佇列裡面去,接下來不就可以直接把這個元素踢出佇列從而模擬出棧了嗎? 步驟1 步驟2 當然完成pop操作後我們還要做一件事情,就是輔助佇列和主佇列互換,以讓未來還能按同樣的流程再來一次。 具體程式碼import java.util.LinkedList; import java.util.Queue; class MyStack { private Queue queue1; private Queue queue2; /** Initialize your data structure here. */ public MyStack() { queue1 = new LinkedList<Integer>(); queue2 = new LinkedList<Integer>(); } /** Push element x onto stack. */ public void push(int x) { queue1.offer(x); } /** Removes the element on top of the stack and returns that element. */ public int pop() { while (queue1.size()>1) { queue2.offer(queue1.poll()); } int result = (Integer) queue1.poll(); Queue temp =queue1; queue1 = queue2; queue2 = temp; return result; } /** Returns whether the stack is empty. */ public boolean empty() { return queue1.isEmpty(); } }
迴圈佇列的實現
設計迴圈佇列的原因 對於普通的單向佇列,在入佇列和出佇列的時候可能會遇到一種“佇列假滿”的現象,導致空間的浪費如下圖所示 所以我們要做的,就是通過設定頭部(front)和尾部(rear)兩個指標來區分佇列的“滿的部分”和“空的部分”,並且允許在填充到陣列末尾的時候,能通過回到陣列的頭部這種迴圈的方式繼續填充陣列,從而提高陣列空間的利用率。 怎麼實現從尾部到頭部的迴圈呢? 我們可以通過取餘運算子實現,因為當 i = 陣列長度- 1的時候,(i + 1) % 陣列長度 = 0,也就是說這個時候指標又從尾部回到了陣列的頭部 具體程式碼class MyCircularQueue { private int [] queue; private int front; private int rear; private int len; /** Initialize your data structure here. Set the size of the queue to be k. */ public MyCircularQueue(int k) { queue = new int[k+1]; // 包含 front = 0; // 不包含 rear = 0; len = k+1; } /** Insert an element into the circular queue. Return true if the operation is successful. */ public boolean enQueue(int value) { if (isFull()) return false; queue[rear] = value; rear =(rear+1) % len; return true; } /** Delete an element from the circular queue. Return true if the operation is successful. */ public boolean deQueue() { if (isEmpty()) return false; queue[front] = -1; front = (front + 1) % len; return true; } /** Get the front item from the queue. */ public int Front() { if (isEmpty()) return -1; return queue[front]; } /** Get the last item from the queue. */ public int Rear() { if (isEmpty()) return -1; if (rear>0) return queue[rear-1]; else return queue[len - 1]; } /** Checks whether the circular queue is empty or not. */ public boolean isEmpty() { if (rear == front) return true; else return false; } /** Checks whether the circular queue is full or not. */ public boolean isFull() { if ((rear + 1)%len== front) return true; else return false; } }
&nbs