数据结构与算法(2)——栈和队列
前言:題圖無(wú)關(guān),只是好看,接下來(lái)就來(lái)復(fù)習(xí)一下棧和隊(duì)列的相關(guān)知識(shí)
前序文章:
- 數(shù)據(jù)結(jié)構(gòu)與算法(1)——數(shù)組與鏈表(https://www.jianshu.com/p/7b93b3570875)
棧
什么是棧
棧是一種用于存儲(chǔ)數(shù)據(jù)的簡(jiǎn)單數(shù)據(jù)結(jié)構(gòu)(與鏈表類似)。數(shù)據(jù)入棧的次序是棧的關(guān)鍵。可以把一桶桶裝的薯片看作是一個(gè)棧的例子,當(dāng)薯片做好之后,它們會(huì)依次被添加到桶里,每一片都會(huì)是當(dāng)前的最上面一片,而每次我們?nèi)〉臅r(shí)候也是取的最上面的那一片,規(guī)定你不能破壞桶也不能把底部捅穿,所以第一個(gè)放入桶的薯片只能最后一個(gè)從桶里取出;
定義:棧(Stack)是一個(gè)有序線性表,只能在表的一端(稱為棧頂,top)執(zhí)行插入和刪除操作。最后插入的元素將第一個(gè)被刪除,所以棧也稱為后進(jìn)先出(Last In First Out,LIFO)或先進(jìn)后出(First In Last Out)線性表;
兩個(gè)改變棧的操作都有專用名稱。一個(gè)稱為入棧(push),表示在棧中插入一個(gè)元素;另一個(gè)稱為出棧(pop),表示從棧中刪除一個(gè)元素。試圖對(duì)一個(gè)空棧執(zhí)行棧操作稱為下溢(underflow);試圖對(duì)一個(gè)滿棧執(zhí)行棧操作稱為溢出(overflow)。通常,溢出和下溢均認(rèn)為是異常;
棧的應(yīng)用
- 無(wú)處不在的Undo操作(撤銷);
- 程序調(diào)用的系統(tǒng)棧;
- 括號(hào)/符號(hào)匹配;
- 等等等等....
棧抽象數(shù)據(jù)類型
下面給出棧抽象數(shù)據(jù)類型中的操作,為了簡(jiǎn)單起見(jiàn),假設(shè)數(shù)據(jù)類型為整型;
棧的主要操作
- void push(int data):將data(數(shù)據(jù))插入棧;
- int pop():刪除并返回最后一個(gè)插入棧的元素;
棧的輔助操作
- int top():返回最后一個(gè)插入棧的元素,但不刪除;
- int size():返回存儲(chǔ)在棧中元素的個(gè)數(shù);
- int isEmpty():判斷棧中是否有元素;
- int isStackFull():判斷棧中是否存滿元素;
動(dòng)態(tài)數(shù)組簡(jiǎn)單實(shí)現(xiàn)棧結(jié)構(gòu)
我們結(jié)合之前創(chuàng)建的Array類,我們能夠很好的創(chuàng)建屬于我們自己的動(dòng)態(tài)數(shù)組實(shí)現(xiàn)的棧結(jié)構(gòu),對(duì)于用戶來(lái)說(shuō),我們只需要完成我們的相關(guān)操作,并且知道我能夠不斷地往里添加元素而不出錯(cuò)就行了,所以我們先來(lái)定義一個(gè)通用的棧接口:
public interface Stack<E> {int getSize();boolean isEmepty();void push(E e);E pop();E top(); }然后我們往之前的動(dòng)態(tài)數(shù)組中添加兩個(gè)用戶友好的方法:
public E getLast() {return get(size - 1); }public E getFirst() {return get(0); }然后實(shí)現(xiàn)自己的動(dòng)態(tài)數(shù)組為底層的棧結(jié)構(gòu)就輕松多了:
public class ArrayStack<E> implements Stack<E> {Array<E> array;public ArrayStack(int capacity) {array = new Array<>(capacity);}public ArrayStack() {array = new Array<>();}@Overridepublic int getSize() {return array.getSize();}@Overridepublic boolean isEmepty() {return array.isEmpty();}public int getCapacity() {return array.getCapacity();}@Overridepublic void push(E e) {array.addLast(e);}@Overridepublic E pop() {return array.removeLast();}@Overridepublic E top() {return array.getLast();}@Overridepublic String toString() {StringBuilder res = new StringBuilder();res.append("Stack:");res.append("[");for (int i = 0; i < array.getSize(); i++) {res.append(array.get(i));if (i != array.getSize() - 1) {res.append(",");}}res.append("]");return res.toString();} }簡(jiǎn)單復(fù)雜度分析
從代碼中可以看出,幾乎所有的時(shí)間復(fù)雜度都為O(1)級(jí)別,比較特別的是push()和pop()操作可能涉及到底層數(shù)組的擴(kuò)容或縮容的操作,所以是均攤下來(lái)的復(fù)雜度;
隊(duì)列
什么是隊(duì)列
隊(duì)列是一種用于存儲(chǔ)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)(與鏈表和棧類似),數(shù)據(jù)到達(dá)的次序是隊(duì)列的關(guān)鍵;在日常生活中隊(duì)列是指從序列的開(kāi)始按照順序等待服務(wù)的一隊(duì)人或物;
定義:隊(duì)列是一種只能在一端插入(隊(duì)尾),在另一端刪除(隊(duì)首)的有序線性表。隊(duì)列中第一個(gè)插入的元素也是第一個(gè)被刪除的元素,所以隊(duì)列是一種先進(jìn)先出(FIFO,First In First Out)或后進(jìn)后出(LiLO,Last In Last Out)線性表;
與棧類似,兩個(gè)改變隊(duì)列的操作各有專用名稱;在隊(duì)列中插入一個(gè)元素,稱為入隊(duì)(EnQueue),從隊(duì)列中刪除一個(gè)元素,稱為出隊(duì)(DeQueue);試圖對(duì)一個(gè)空隊(duì)列執(zhí)行出隊(duì)操作稱為下溢(underflow),試圖對(duì)一個(gè)滿隊(duì)列執(zhí)行入隊(duì)操作稱為溢出(overflow);通常認(rèn)為溢出和下溢是異常。
隊(duì)列的一些應(yīng)用舉例
- 操作系統(tǒng)根據(jù)(具有相同優(yōu)先級(jí)的)任務(wù)到達(dá)的順序調(diào)度任務(wù)(例如打印隊(duì)列);
- 模擬現(xiàn)實(shí)世界中的隊(duì)列,如售票柜臺(tái)前的隊(duì)伍,或者任何需要先來(lái)先服務(wù)的場(chǎng)景;
- 多道程序設(shè)計(jì);
- 異步數(shù)據(jù)傳輸(文件輸入輸出、管道、套接字);
- 等等等等...
動(dòng)態(tài)數(shù)組簡(jiǎn)單實(shí)現(xiàn)隊(duì)列結(jié)構(gòu)
我們?nèi)匀欢x一個(gè)Queue接口來(lái)說(shuō)明我們隊(duì)列中常用的一些方法:
public interface Queue<E> {int getSize();boolean isEmpty();void enqueue(E e);E dequeue();E getFront(); }借由我們之前自己實(shí)現(xiàn)的動(dòng)態(tài)數(shù)組,那么我們的隊(duì)列就很簡(jiǎn)單了:
public class ArrayQueue<E> implements Queue<E> {private Array<E> array;public ArrayQueue(int capacity){array = new Array<>(capacity);}public ArrayQueue(){array = new Array<>();}@Overridepublic int getSize(){return array.getSize();}@Overridepublic boolean isEmpty(){return array.isEmpty();}public int getCapacity(){return array.getCapacity();}@Overridepublic void enqueue(E e){array.addLast(e);}@Overridepublic E dequeue(){return array.removeFirst();}@Overridepublic E getFront(){return array.getFirst();}@Overridepublic String toString(){StringBuilder res = new StringBuilder();res.append("Queue: ");res.append("front [");for(int i = 0 ; i < array.getSize() ; i ++){res.append(array.get(i));if(i != array.getSize() - 1)res.append(", ");}res.append("] tail");return res.toString();} }簡(jiǎn)單的復(fù)雜度分析
- void enquque(E):O(1)(均攤)
- E dequeue():O(n)
- E front():O(1)
- int getSize():O(1)
- boolean isEmpty():O(1)
實(shí)現(xiàn)自己的循環(huán)隊(duì)列
循環(huán)隊(duì)列的實(shí)現(xiàn)其實(shí)就是維護(hù)了一個(gè)front和一個(gè)tail分別指向頭和尾,然后需要特別注意的呢是判定隊(duì)滿和隊(duì)空的條件:
- 隊(duì)空:front == tail,這沒(méi)啥好說(shuō)的;
- 隊(duì)滿:tail + 1 == front,這里其實(shí)是有意浪費(fèi)了一個(gè)空間,不然就判定不了到底是隊(duì)空還是隊(duì)滿了,因?yàn)闂l件都一樣...
簡(jiǎn)單復(fù)雜度分析
- void enquque(E):O(1)(均攤)
- E dequeue():O(1)(均攤)
- E front():O(1)
- int getSize():O(1)
- boolean isEmpty():O(1)
簡(jiǎn)單數(shù)組隊(duì)列和循環(huán)隊(duì)列的簡(jiǎn)單比較
我們來(lái)簡(jiǎn)單對(duì)比一下兩個(gè)隊(duì)列的性能吧,這里直接上代碼:
// 測(cè)試使用q運(yùn)行opCount個(gè)enqueueu和dequeue操作所需要的時(shí)間,單位:秒 private static double testQueue(Queue<Integer> q, int opCount){long startTime = System.nanoTime();Random random = new Random();for(int i = 0 ; i < opCount ; i ++)q.enqueue(random.nextInt(Integer.MAX_VALUE));for(int i = 0 ; i < opCount ; i ++)q.dequeue();long endTime = System.nanoTime();return (endTime - startTime) / 1000000000.0; }public static void main(String[] args) {int opCount = 100000;ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();double time1 = testQueue(arrayQueue, opCount);System.out.println("ArrayQueue, time: " + time1 + " s");LoopQueue<Integer> loopQueue = new LoopQueue<>();double time2 = testQueue(loopQueue, opCount);System.out.println("LoopQueue, time: " + time2 + " s"); }我這里的測(cè)試結(jié)果是這樣的,大家也就可見(jiàn)一斑啦:
其實(shí)ArrayQueue慢主要是因?yàn)槌鰲r(shí)每次都需要把整個(gè)結(jié)構(gòu)往前挪一下
LeetCode 相關(guān)題目整理
20.有效的括號(hào)
我的答案:(10ms)
public boolean isValid(String s) {// 正確性判斷if (null == s || s.length() == 1) {return false;}Stack<Character> stack = new Stack<>();// 遍歷輸入的字符for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);// 如果為左括號(hào)則push進(jìn)棧if (c == '(' || c == '[' || c == '{') {stack.push(c);} else {if (stack.isEmpty()) {return false;}char topChar = stack.pop();if (c == ')' && topChar != '(') {return false;}if (c == ']' && topChar != '[') {return false;}if (c == '}' && topChar != '{') {return false;}}}// 最后棧為空才能返回truereturn stack.isEmpty(); }參考答案:(8ms)
public boolean isValid(String s) {// 正確性判斷if (0 == s.length()) {return true;}if (s.length() % 2 == 1) {return false;}Stack<Character> stack = new Stack();char[] cs = s.toCharArray();for (int i = 0; i < cs.length; i++) {if (cs[i] == '(' || cs[i] == '[' || cs[i] == '{') {stack.push(cs[i]);} else {if (stack.isEmpty()) {return false;}char c = stack.pop();if ((cs[i] == ')' && c == '(') || (cs[i] == '}' && c == '{') || (cs[i] == ']' && c == '[')) {} else {return false;}}}return stack.isEmpty(); }155. 最小棧(劍指Offer面試題30)
參考答案(107ms)
class MinStack {// 數(shù)據(jù)棧,用于存放插入的數(shù)據(jù)private Stack<Integer> dataStack;// 最小數(shù)位置棧,存放數(shù)據(jù)棧中最小的數(shù)的位置private Stack<Integer> minStack;/*** initialize your data structure here.*/public MinStack() {this.dataStack = new Stack<>();this.minStack = new Stack<>();}/*** 元素入棧** @param x 入棧的元素*/public void push(int x) {dataStack.push(x);// 如果最小棧是空的,只要將元素入棧if (minStack.isEmpty()) {minStack.push(x);}// 如果最小棧中有數(shù)據(jù)else {minStack.push(Math.min(x, minStack.peek()));}}/*** 出棧方法*/public void pop() {// 如果棧已經(jīng)為空,則返回(LeetCode不能拋異常...)if (dataStack.isEmpty()) {return;}// 如果有數(shù)據(jù),最小數(shù)位置棧和數(shù)據(jù)棧必定是有相同的元素個(gè)數(shù),// 兩個(gè)棧同時(shí)出棧minStack.pop();dataStack.pop();}/*** 返回棧頂元素** @return 棧頂元素*/public int top() {return dataStack.peek();}/*** 獲取棧中的最小元素** @return 棧中的最小元素*/public int getMin() {// 如果最小數(shù)公位置棧已經(jīng)為空(數(shù)據(jù)棧中已經(jīng)沒(méi)有數(shù)據(jù)了),則拋出異常if (minStack.isEmpty()) {return 0;}// 獲取數(shù)據(jù)占中的最小元素,并且返回結(jié)果return minStack.peek();} }改進(jìn)答案:
上面求解方法的主要問(wèn)題在于,每次push操作時(shí),minStack也執(zhí)行了一次push操作(新元素或當(dāng)前的最小元素),也就是說(shuō),重復(fù)執(zhí)行了最小值的入棧操作,所以現(xiàn)在我們來(lái)修改算法降低空間復(fù)雜度。仍然需要設(shè)置一個(gè)minStack,但是只有當(dāng)從dataStack中出棧的元素等于minStack棧頂元素時(shí),才對(duì)minStack執(zhí)行出棧的操作;也只有當(dāng)dataStack入棧的元素小于或等于當(dāng)前最小值時(shí),才對(duì)minStack執(zhí)行入棧操作,下面就簡(jiǎn)單寫(xiě)一下了主要看一下出棧和入棧實(shí)現(xiàn)的邏輯就好了:
class MinStack {private Stack<Integer> dataStack;private Stack<Integer> minStack;public MinStack() {this.dataStack = new Stack<>();this.minStack = new Stack<>();}public void push(int x) {dataStack.push(x);if (minStack.isEmpty() || minStack.peek() >= (Integer) x) {minStack.push(x);}}public void pop() {if (dataStack.isEmpty()) {return;}Integer minTop = minStack.peek();Integer dataTop = dataStack.peek();if (minTop.intValue() == dataTop.intValue()) {minStack.pop();}dataStack.pop();}public int top() {return dataStack.peek();}public int getMin() {return minStack.peek();} }225. 用隊(duì)列實(shí)現(xiàn)棧
我的答案:(118ms)
class MyStack {private Queue<Integer> queue1;private Queue<Integer> queue2;/*** Initialize your data structure here.*/public MyStack() {queue1 = new LinkedList<>();queue2 = new LinkedList<>();}/*** Push element x onto stack.*/public void push(int x) {if (queue1.isEmpty()) {queue2.offer(x);} else {queue1.offer(x);}}/*** Removes the element on top of the stack and returns that element.*/public int pop() {int size;if (!queue1.isEmpty()) {size = queue1.size();for (int i = 0; i < size - 1; i++) {queue2.offer(queue1.poll());}return queue1.poll();} else {size = queue2.size();for (int i = 0; i < size - 1; i++) {queue1.offer(queue2.poll());}return queue2.poll();}}/*** Get the top element.*/public int top() {int size;if (!queue1.isEmpty()) {size = queue1.size();for (int i = 0; i < size - 1; i++) {queue2.offer(queue1.poll());}int result = queue1.peek();queue2.offer(queue1.poll());return result;} else {size = queue2.size();for (int i = 0; i < size - 1; i++) {queue1.offer(queue2.poll());}int result = queue2.peek();queue1.offer(queue2.poll());return result;}}/*** Returns whether the stack is empty.*/public boolean empty() {return queue1.isEmpty() && queue2.isEmpty();} }參考答案:(121ms)
class MyStack {Queue<Integer> q;/*** Initialize your data structure here.*/public MyStack() {this.q = new LinkedList<Integer>();}/*** Push element x onto stack.*/public void push(int x) {q.add(x);}/*** Removes the element on top of the stack and returns that element.*/public int pop() {int size = q.size();for (int i = 0; i < size - 1; i++) {q.add(q.remove());}return q.remove();}/*** Get the top element.*/public int top() {int size = q.size();for (int i = 0; i < size - 1; i++) {q.add(q.remove());}int ret = q.remove();q.add(ret);return ret;}/*** Returns whether the stack is empty.*/public boolean empty() {return q.isEmpty();} }確實(shí)寫(xiě)得簡(jiǎn)潔啊,這樣一來(lái)我就使用一個(gè)隊(duì)列和兩個(gè)隊(duì)列都掌握啦,開(kāi)心~
232.用棧實(shí)現(xiàn)隊(duì)列(劍指Offer面試題9)
參考答案:(72ms)
class MyQueue {Stack<Integer> pushstack;Stack<Integer> popstack;/*** Initialize your data structure here.*/public MyQueue() {this.pushstack = new Stack();this.popstack = new Stack();}/*** Push element x to the back of queue.*/public void push(int x) {pushstack.push(x);}/*** Removes the element from in front of queue and returns that element.*/public int pop() {if (popstack.isEmpty()) {while (!pushstack.isEmpty()) {popstack.push(pushstack.pop());}}return popstack.pop();}/*** Get the front element.*/public int peek() {if (popstack.isEmpty()) {while (!pushstack.isEmpty()) {popstack.push(pushstack.pop());}}return popstack.peek();}/*** Returns whether the queue is empty.*/public boolean empty() {return pushstack.isEmpty() && popstack.isEmpty();} }其他題目整理
劍指Offer面試題31:棧的壓入、彈出序列
題目:輸入兩個(gè)整數(shù)序列,第一個(gè)序列表示棧的壓入順序,請(qǐng)判斷第二個(gè)序列是否為該棧的彈出順序。假設(shè)壓入棧的所有數(shù)字均不相等。例如,序列{1,2,3,4,5}是某棧的壓棧序列,序列{4,5,3,2,1}是該壓棧序列對(duì)應(yīng)的一個(gè)彈出序列,但{4,3,5,1,2}就不可能是該壓棧序列的彈出序列。
參考答案:(原文鏈接:https://blog.csdn.net/derrantcm/article/details/46691083)
public class Test22 {/*** 輸入兩個(gè)整數(shù)序列,第一個(gè)序列表示棧的壓入順序,請(qǐng)判斷二個(gè)序列是否為該棧的彈出順序。* 假設(shè)壓入棧的所有數(shù)字均不相等。例如序列1 、2、3 、4、5 是某棧壓棧序列,* 序列4、5、3、2、1是該壓棧序列對(duì)應(yīng)的一個(gè)彈出序列,* 但4、3、5、1、2就不可能是該壓棋序列的彈出序列。* 【與書(shū)本的的方法不同】** @param push 入棧序列* @param pop 出棧序列* @return true:出棧序列是入棧序列的一個(gè)彈出順序*/public static boolean isPopOrder(int[] push, int[] pop) {// 輸入校驗(yàn),參數(shù)不能為空,并且兩個(gè)數(shù)組中必須有數(shù)字,并且兩個(gè)數(shù)組中的數(shù)字個(gè)數(shù)相同// 否則返回falseif (push == null || pop == null || pop.length == 0 || push.length == 0 || push.length != pop.length) {return false;}// 經(jīng)過(guò)上面的參數(shù)校驗(yàn),兩個(gè)數(shù)組中一定有數(shù)據(jù),且數(shù)據(jù)數(shù)目相等// 用于存放入棧時(shí)的數(shù)據(jù)Stack<Integer> stack = new Stack<>();// 用于記錄入棧數(shù)組元素的處理位置int pushIndex = 0;// 用于記錄出棧數(shù)組元素的處理位置int popIndex = 0;// 如果還有出棧元素要處理while (popIndex < pop.length) {// 入棧元素還未全部入棧的條件下,如果棧為空,或者棧頂?shù)脑夭慌c當(dāng)前處理的相等,則一直進(jìn)行棧操作,// 直到入棧元素全部入?;蛘哒业搅艘粋€(gè)與當(dāng)出棧元素相等的元素while (pushIndex < push.length && (stack.isEmpty() || stack.peek() != pop[popIndex])) {// 入棧數(shù)組中的元素入棧stack.push(push[pushIndex]);// 指向下一個(gè)要處理的入棧元素pushIndex++;}// 如果在上一步的入棧過(guò)程中找到了與出棧的元素相等的元素if (stack.peek() == pop[popIndex]) {// 將元素出棧stack.pop();// 處理下一個(gè)出棧元素popIndex++;}// 如果沒(méi)有找到與出棧元素相等的元素,說(shuō)明這個(gè)出棧順序是不合法的// 就返回falseelse {return false;}}// 下面的語(yǔ)句總是成立的// return stack.isEmpty();// 為什么可以直接返回true:對(duì)上面的外層while進(jìn)行分析可知道,對(duì)每一個(gè)入棧的元素,// 在stack棧中,通過(guò)一些入棧操作,總可以在棧頂上找到與入棧元素值相同的元素,// 這就說(shuō)明了這個(gè)出棧的順序是入棧順序的一個(gè)彈出隊(duì)列,這也可以解釋為什么stack.isEmpty()// 總是返回true,所有的入棧元素都可以進(jìn)棧,并且可以被匹配到,之后就彈出,最后棧中就無(wú)元素。return true;}/*** 輸入兩個(gè)整數(shù)序列,第一個(gè)序列表示棧的壓入順序,請(qǐng)判斷二個(gè)序列是否為該棧的彈出順序。* 【按書(shū)本上的思路進(jìn)行求解,兩者相差不大】** @param push 入棧序列* @param pop 出棧序列* @return true:出棧序列是入棧序列的一個(gè)彈出順序*/public static boolean isPopOrder2(int[] push, int[] pop) {// 用于記錄判斷出棧順序是不是入棧順的一個(gè)出棧序列,默認(rèn)falseboolean isPossible = false;// 當(dāng)入棧和出棧數(shù)組者都不為空,并且都有數(shù)據(jù),并且數(shù)據(jù)個(gè)數(shù)都相等if (push != null && pop != null && push.length > 0 && push.length == pop.length) {// 用于存放入棧時(shí)的數(shù)據(jù)Stack<Integer> stack = new Stack<>();// 記錄下一個(gè)要處理的入棧元素的位置int nextPush = 0;// 記錄下一個(gè)要處理的出棧元素的位置int nextPop = 0;// 如果出棧元素沒(méi)有處理完就繼續(xù)進(jìn)行處理while (nextPop < pop.length) {// 如果棧為空或者棧頂?shù)脑嘏c當(dāng)前處理的出棧元素不相同,一直進(jìn)行操作while (stack.isEmpty() || stack.peek() != pop[nextPop]) {// 如果入棧的元素已經(jīng)全部入棧了,就退出內(nèi)層循環(huán)if (nextPush >= push.length) {break;}// 執(zhí)行到此處說(shuō)明還有入棧元素可以入棧// 即將元素入棧stack.push(push[nextPush]);// 指向下一個(gè)要處理的入棧元素的位置nextPush++;}// 執(zhí)行到此處有兩種情況:// 第一種:在棧頂上找到了一個(gè)與入棧元素相等的元素// 第二種:在棧頂上沒(méi)有找到一個(gè)與入棧元素相等的元素,而且輸入棧的元素已經(jīng)全部入棧了// 對(duì)于第二種情況就說(shuō)彈出棧的順序是不符合要求的,退出外層循環(huán)if (stack.peek() != pop[nextPop]) {break;}// 對(duì)應(yīng)到第一種情況:需要要棧的棧頂元素彈出stack.pop();// 指向下一個(gè)要處理的出棧元素的位置nextPop++;}// 執(zhí)行到此處有兩種情況// 第一種:外層while循環(huán)的在第一種情況下退出,// 第二種:所有的出棧元素都被正確匹配// 對(duì)于出現(xiàn)的第一種情況其stack.isEmpty()必不為空,原因?yàn)榉治鋈缦?#xff1a;// 所有的入棧元素一定會(huì)入棧,但是只有匹配的情況下才會(huì)出棧,// 匹配的次數(shù)最多與入棧元素個(gè)數(shù)元素相同(兩個(gè)數(shù)組的長(zhǎng)度相等),如果有不匹配的元素,// 必然會(huì)使出棧的次數(shù)比入棧的次數(shù)少,這樣棧中至少會(huì)有一個(gè)元素// 對(duì)于第二種情況其stack.isEmpty()一定為空// 所以書(shū)本上的nextPop == pop.length(pNextPop-pPop==nLength)是多余的if (stack.isEmpty()) {isPossible = true;}}return isPossible;}public static void main(String[] args) {int[] push = {1, 2, 3, 4, 5};int[] pop1 = {4, 5, 3, 2, 1};int[] pop2 = {3, 5, 4, 2, 1};int[] pop3 = {4, 3, 5, 1, 2};int[] pop4 = {3, 5, 4, 1, 2};System.out.println("true: " + isPopOrder(push, pop1));System.out.println("true: " + isPopOrder(push, pop2));System.out.println("false: " + isPopOrder(push, pop3));System.out.println("false: " + isPopOrder(push, pop4));int[] push5 = {1};int[] pop5 = {2};System.out.println("false: " + isPopOrder(push5, pop5));int[] push6 = {1};int[] pop6 = {1};System.out.println("true: " + isPopOrder(push6, pop6));System.out.println("false: " + isPopOrder(null, null));// 測(cè)試方法2System.out.println();System.out.println("true: " + isPopOrder2(push, pop1));System.out.println("true: " + isPopOrder2(push, pop2));System.out.println("false: " + isPopOrder2(push, pop3));System.out.println("false: " + isPopOrder2(push, pop4));System.out.println("false: " + isPopOrder2(push5, pop5));System.out.println("true: " + isPopOrder2(push6, pop6));System.out.println("false: " + isPopOrder2(null, null));} }簡(jiǎn)單總結(jié)
棧和隊(duì)列的應(yīng)用遠(yuǎn)不止上面學(xué)習(xí)到的那些,實(shí)現(xiàn)方式也有很多種,現(xiàn)在也只是暫時(shí)學(xué)到這里,通過(guò)刷LeetCode也加深了我對(duì)于這兩種數(shù)據(jù)結(jié)構(gòu)的認(rèn)識(shí),不過(guò)自己還需要去熟悉了解一下計(jì)算機(jī)系統(tǒng)關(guān)于棧的應(yīng)用這方面的知識(shí),因?yàn)闂_@種結(jié)構(gòu)本身就很適合用來(lái)保存CPU現(xiàn)場(chǎng)之類的工作,還是抓緊時(shí)間吧,過(guò)兩天還考試,這兩天就先復(fù)習(xí)啦...
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處!
簡(jiǎn)書(shū)ID:@我沒(méi)有三顆心臟
github:wmyskxz
總結(jié)
以上是生活随笔為你收集整理的数据结构与算法(2)——栈和队列的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 数据结构与算法(1)——数组与链表
- 下一篇: 数据结构与算法(3)——树(二叉、二叉搜