日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《算法(第四版)》1.3.49:有限个栈实现队列,练习题学习小结

發(fā)布時間:2024/3/12 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《算法(第四版)》1.3.49:有限个栈实现队列,练习题学习小结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

用有限個棧實現(xiàn)一個隊列,保證每次出隊和入隊(在最壞的情況下)都只需要常數(shù)次的棧操作。

本文參考了下面兩篇博客,解決這個問題的思路可以閱讀這兩篇博客,本文不在贅述。在核心思路不變的情況下,本文用Java進行了實現(xiàn)。
這篇思路更清晰 https://www.cnblogs.com/dacc123/p/10574939.html
特別感謝沈星繁的幫助 https://www.cnblogs.com/ikesnowy/p/7157813.html#4287263

前一篇文章用兩個棧實現(xiàn)了隊列,但是在某些情況下它的時間復(fù)雜度是O(N),如下面這種情況,當(dāng)從st中出隊完成后,需要將s中的元素逐一倒入st,這個過程的時間復(fù)雜度是O(N),如左圖所示。將s中的元素倒入st的原因是需要對翻轉(zhuǎn)該序列,如果隊列中有N個元素,翻轉(zhuǎn)序列前后至少需要N步,所以保證每次出隊入隊都只需要常數(shù)次操作的本質(zhì)愛是將這N步分配到每次的出隊和入隊中,一理想狀況如右圖所示。

? ?

算法的目的為了讓隊列中的元素能在每次出隊入隊操作中有序地在若干個棧中流動起來。實際上六個棧就能完成元素的調(diào)度,其中一個為臨時棧,用于棧與棧之間的交換(swap),它的作用類似一個指針。
若只考慮進隊,則有圖(左),元素有序地調(diào)度,最終的目的是讓元素集中在棧H和棧T中。這種方式不能滿足隨時出棧的要求,隊列需要做好隨時出棧的準(zhǔn)備。規(guī)定元素總是從H出隊,則有圖(右)。

? ?

讀取H中的元素并保留的方法是peek,需要在棧Stack類中加入一個游標(biāo)cursor來實現(xiàn)peek,只讀取元素而不彈出,每次peek后游標(biāo)移動至下一個元素。

Item item = cursor.item; cursor = cursor.next; return item;

各個棧的作用:①H:元素總是從H出隊,棧頂為先入隊的元素;②T,Tadd:入隊的元素先被儲存在這兩個棧,在需要的時候Tadd中的元素會“復(fù)制”到T;③Hflip:棧H的翻轉(zhuǎn),H中的元素被逐一peek壓入棧Hflip;④Hbuffer:T中的元素會逐一pop壓入棧Hbuffer,Hflip中的元素也會被逐一pop壓入棧Hbuffer,在需要的時候Hbuffer中的元素會“復(fù)制”到H。⑤sp:臨時棧,可視為一個指針,用于兩個棧的復(fù)制替換。
入隊遵循先入隊再整理的基本原則,細(xì)則如下:
1.如果Hbuffer非空則入隊至棧T,否則入隊至棧Tadd。
2.一次入隊完成后緊接著對各個棧進行整理。
3.if T非空,則棧頂?shù)脑豴op后push入Hbuffer or H中仍有元素未被peek完全
??do peek出元素push入Hflip(這種情況出現(xiàn)在出隊后繼續(xù)入隊)
?? if T和Hflip都為空(此時H一定為空)
???do 復(fù)制Hbuffer并替換H,復(fù)制Tadd并替換T
?else if T為空
??if Hflip不為空? do 將Hflip棧頂元素pop后push入Hbuffer
???if T和Hflip都為空(此時H一定為空)? do 復(fù)制Hbuffer并替換H,復(fù)制Tadd并替換T
?else if T,Hflip,H都為空? do 復(fù)制Hbuffer并替換H,復(fù)制Tadd并替換T
4.復(fù)制Hbuffer并替換H,這個需要用到臨時棧sp。

sp = H; H = Hbuffer; Hbuffer = sp;

每次復(fù)制替換后都需要統(tǒng)計H和T中元素的總個數(shù)popCnt,這個過程被整合到swap函數(shù)。當(dāng)新的元素入隊時進入T,popCnt++。popCnt與出隊有關(guān),下文將進行解釋。

出隊遵循先出隊后整理的基本原則,細(xì)則如下:
1.總是從H出隊,若H為空,則隊列為空;出隊后馬上將T棧頂?shù)脑豴op后push入Hbuffer(如果T非空),出隊后popCnt–。
2.出隊后進行整理。
3.if H為空
??if 隊列不為空? do swap。
?else
??if T為空
???if 下一個出隊的元素就是Hbuffer棧頂?shù)脑?do swap,清空Hflip
???else ?do 將Hflip棧頂?shù)脑豴op后push入Hbuffer
4.由于Hflip中的元素是H被peek后push的,所以被從Hflip棧頂pop出的元素可能是已經(jīng)出隊的元素。為了避免這種情況的出現(xiàn),引入了變量popCnt。swap時,Hbuffer的元素實際上都是來自H和T,是一個階段內(nèi)入隊的元素。當(dāng)下面的判斷式為真時,說明下一個出隊的元素就是Hbuffer棧頂?shù)脑?#xff0c;此時需要swap并清空Hflip。

Hbuffer.size() + H.size() > popCnt && popCnt - Hbuffer.size() <=1

5.清空棧的方法如下,時間復(fù)雜度也為常數(shù)。

first = new Node(); cursor = first; N = 0;

主要部分代碼如下:

public class StackQueue<Item> {private Stack<Item> H = new Stack<Item>();private Stack<Item> T = new Stack<Item>();private Stack<Item> Hbuffer = new Stack<Item>();private Stack<Item> Hflip = new Stack<Item>();private Stack<Item> Tadd = new Stack<Item>();private Stack<Item> sp;private int popCnt;private int N = 0;private int sizeofH = 0; //被peek后H中剩余的元素個數(shù)public boolean isEmpty() {return H.isEmpty() && T.isEmpty() && Hbuffer.isEmpty()&& Hflip.isEmpty() && Tadd.isEmpty();}public int size() {return N;}private void popPush(Stack<Item> s1, Stack<Item> s2) { //s1彈出一個元素后壓入s2if(!s1.isEmpty())s2.push(s1.pop());}private void peekPush(Stack<Item> s1, Stack<Item> s2) { //H peek一個元素后壓入Hflipif(!s1.isEmpty() && sizeofH > 0) {s2.push(s1.peek());sizeofH --;}}private void swap() {H.clear(); sp = H; H = Hbuffer; Hbuffer = sp;T.clear(); sp = T; T = Tadd; Tadd = sp;popCnt = H.size() + T.size();sizeofH = H.size();}public void enQueue(Item item) {//入隊if(Hbuffer.isEmpty()) {T.push(item);popCnt ++;} elseTadd.push(item);//整理//sizeofH < T.size() 說明H未peek完全,T中仍有元素,需要移動//sizeofH >= H.size() && T.isEmpty() 說明H中還有元素在被peek前先被pop,需要移動if(!T.isEmpty() || (sizeofH >= H.size() && T.isEmpty())) {popPush(T, Hbuffer); peekPush(H, Hflip);if(T.isEmpty() && Hflip.isEmpty())swap();} else if(T.isEmpty()) {if(!Hflip.isEmpty()) {popPush(Hflip, Hbuffer);if(Hflip.isEmpty() && T.isEmpty())swap();} else if(Hflip.isEmpty() && T.isEmpty() && H.isEmpty())swap();}N ++;}public Item deQueue() {Item item;//先出if(!H.isEmpty()) {item = H.pop();popCnt --;popPush(T, Hbuffer);}else item = null;//出完后整理if(H.isEmpty()) { //H為空if(N > 0 ) { //還有元素swap(); Hflip.clear();}} else { //H不為空if(T.isEmpty()) { //T為空if(Hbuffer.size() + H.size() > popCnt && popCnt - Hbuffer.size() <=1) {swap(); Hflip.clear();} else if(popCnt < H.size() + Hbuffer.size())popPush(Hflip, Hbuffer);}}N --; return item;} }

《算法(第四版)》部分練習(xí)題索引

總結(jié)

以上是生活随笔為你收集整理的《算法(第四版)》1.3.49:有限个栈实现队列,练习题学习小结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。