【死磕演算法·棧和佇列】僅用遞迴實現棧的逆序
題目要求:實現棧的逆序,但只能用遞迴函式和這個棧本身操作來實現,不能自己申請額外的資料結構。
題目思路:
實現兩個遞迴函式:
getBottomItem():移除棧底元素並返回該元素
reverse():實現整個棧逆序
如何寫遞迴函式?
遞迴函式在函式體中呼叫自己,對不同的值進行重複操作。
遞迴函式三要素:
1、要有可以退出函式的情況;
2、遞迴過程中將一個問題簡化到更小的規模,遞迴函式的引數規模一定是越來越小的
3、父問題和子問題不能有重疊。
但更重要的是,得知道遞迴半天,寫這個函式最後要返回什麼或者達成什麼效果,進而思考要怎樣一步步
getBottomItem():
這個函式的目的是要得到棧底元素並移除,分三步走:
1、把棧底元素上面的元素一個個的都彈出來;
2、得到並移除棧底元素;
3、將之前在棧底元素上面的元素再壓回棧中去。
遞迴總要有個結尾,如果把遞迴函式比作”俄羅斯套娃“,我們得不斷把外殼拿掉直到得到最小的”實心娃娃“,這個遞迴函式的結尾在於得到並移除棧底元素。那麼我們由函式體前幾行就已經確定了:
public int getBottomItem(stack<int> s){ int nowItem = s.pop(); if(s.isEmpty()){ //遞迴到底要執行的操作 return nowItem; } else{ ... } }
接下來我們填else 括號體的內容:
首先,函式不繼續遞迴無法觸底,把新棧作為引數繼續呼叫遞迴函式,遞迴函式觸底返回到這一層時會把棧底元素也返回,因此int last = getBottomItem(s)來儲存返回的棧底元素值。
看遞迴到底已經獲得棧底元素之後,我們應該做什麼——把原來在棧底元素上面的元素按原來順序壓入棧中。
我們已經獲得了這一層裡移除的非棧底元素nowItem,接下來要把這一層的nowItem壓入棧中 s.push(nowItem)
返回到遞迴函式的最頂層,遞迴函式把原來的棧頂元素重新壓入到棧中,
不要忘了我們還在遞迴函式內,而最後的目標是返回棧底元素,因此函式最後返回棧底元素last。
最後getBottomItem()實現如下:
public int getBottomItem(stack<int> s){
int nowItem = s.pop();
if(s.isEmpty())//遞迴到底
return nowItem;
else{//
int last = getBottomItem(s)//沒遞迴到底的時候,我們要用一個變數儲存返回的棧底元素;
s.push(nowItem)//把這一層的棧元素壓入棧中
return last;
}
}
我們再來看reverse()函式。
reverse函式的目的是讓棧逆序,棧頂元素要在棧底。同樣的我們首先將這個問題拆解成步驟:
1、呼叫getBottomItem獲取棧底元素並移除,直到我們得到棧頂元素並移除,此時棧為空,遞迴到底
2、把棧頂元素壓入棧底,其他元素按照最後後移除的先入棧的原則入棧,實現棧的逆序。
public void reverse(stack <int> s){
if(s.isEmpty())
return;
int bottom = getBottomItem(s);
reverse(s);
s.push(bottom);
}
在向下一層層遞迴中棧底元素被移除,直到棧中只有棧頂元素,棧頂元素被移除後繼續遞迴,棧為空,此時遞迴函式開始向上返回。
返回上一層後,bottom值即為原棧頂值,注意到此時棧為空,要把他壓入棧底,即s.push(bottom)
總結
寫遞迴函式只要考慮到:
1、遞迴函式向下遞迴終結的條件是什麼,要返回什麼,把這段程式碼寫在函式題的前面。
2、向下遞迴結束開始向上返回時,假設只到了觸底反彈的上一層, 考慮我們在遞迴結果的基礎上如何操作,寫在“自己呼叫自己”的下面。
以下是一個遞迴函式體內部的必要步驟和前後邏輯:
Public int recursiveFunction(s): |
1、獲取遞迴函式觸底時需要返回的值(可選) |
2、通常以if語句開頭,向下遞迴的終結條件及返回(如果遞迴函式需要返回某值,在這之前要獲取該值) |
3、通常以else語句開頭,在呼叫自己之前保證對引數s進行過處理,使其規模簡化。 |
4、recursiveFunction(s) |
5、向下遞迴到底,向上返回時到上一層,考慮要在向下遞迴到底的基礎上進行什麼操作。 |
6、返回遞迴函式從最底端開始往上傳遞的值(可選) |
棧逆序程式碼實現:
class StackReverse {
public:
int getBottomItem(vector <int> &s){
int nowItem = s.back();//返回最後向量尾部最後一個元素
s.pop_back();//從向量尾部彈出一個元素
if(s.empty())//遞迴到底
return nowItem;
else{//
int last = getBottomItem(s);//沒遞迴到底的時候,我們要用一個變數儲存返回的棧底元素;
s.push_back(nowItem);//把這一層的棧元素壓入棧中,用vector的push_back()函式實現,向向量尾部增加一個元素
return last;
}
}
void reverse(vector <int> &s){
if(s.empty())
return;
else{
int bottom = getBottomItem(s);
reverse(s);
s.push_back(bottom);//自下向上把後彈出的值先壓入棧中,實現逆序
}
}
vector<int> reverseStack(vector<int> A, int n) {
// write code here
reverse(A);
return A;
}
};