每日算法之4
1.使用兩個棧實現一個隊列
//基礎知識:由於棧具有先進後出的特點,如果需要在棧中尋找指定元素,需要的時間複雜度爲O(n),如果需要在
//O(1)的時間訪問,必須對棧結構進行改進,需要設計兩個棧,一個負責存儲,另一個複雜存儲最小值
//問題描述:使用兩個棧實現一個隊列的功能
//算法分析:由於棧先進後出,只需要設計兩個棧,將元素推入一個棧s1,出棧推入s2,之後從s2出棧,反反得正
//算法實現:
template<typename T>
class CQueue{
public:
void appendTail(const T&);//請實現次隊列的尾部插入元素和頭部刪除元素的函數
T deleteHead();
void show();
private:
stack<T> stack1;
stack<T> stack2;
};
template<typename T>
void CQueue<T>::appendTail(const T& e){
stack1.push(e);//尾部插入只需要推入棧1即可
}
template<typename T>
T CQueue<T>::deleteHead(){
if(stack2.empty()){
while(!stack1.empty()){
T& data=stack1.top();
stack1.pop();
stack2.push(data);
}
}
if(stack2.empty())
throw "queue is empty!";
T head=stack2.top();
stack2.pop();
return head;
}
template<typename T>
void CQueue<T>::show(){
cout<<"stack1 size of:"<<stack1.size()<<endl;
cout<<"stack2 size of:"<<stack2.size()<<endl;
}
//測試用例:
#include <iostream>
#include <stack>
#include <exception>
int main(){
CQueue<int> queue;
queue.appendTail(2);
queue.appendTail(4);
queue.show();
try{
queue.deleteHead();
queue.show();
queue.deleteHead();
queue.show();
queue.deleteHead();
}catch(const char* e){
cout<<e;
}
}
2.使用兩個隊列實現一個棧
//由於兩個隊列都是先進先出,所以直接相連,無法直接正正得負,所以必須重新分析,考慮到依次入隊q1元素
//1,2,3,4想要出棧時刪除4,必須先將1,2,3出隊,依次放入q2,最後才能刪除4,也就是說,必須
//分兩種隊列,一種用於接受新入隊的元素,刪除時,需要另外一個空隊列作爲接受前面元素的輔助隊列
//算法實現:
template<typename T>
class CStack{
public:
void Cpush(const T&);
T& Cpop();
void show();
private:
queue<T> m_q1;
queue<T> m_q2;
};
template<typename T>
void CStack<T>::Cpush(const T& e){
if(m_q1.empty()){
m_q2.push(e);
}
else if(m_q2.empty()){
m_q1.push(e);
}else{
throw "push error!";
}
}
template<typename T>
T& CStack<T>::Cpop(){
if(m_q1.empty()&&m_q2.empty()){
throw "pop error!";
}
if(m_q1.empty()){
while(m_q2.size()!=1){
T& data=m_q2.front();
m_q2.pop();
m_q1.push(data);
}
T& popElem=m_q2.front();
m_q2.pop();
return popElem;
}else{
while(m_q1.size()!=1){
T& data=m_q1.front();
m_q1.pop();
m_q2.push(data);
}
T& popElem=m_q1.front();
m_q1.pop();
return popElem;
}
}
template<typename T>
void CStack<T>::show(){
cout<<"隊列1的元素大小:"<<m_q1.size()<<endl;
cout<<"隊列2的元素大小:"<<m_q2.size()<<endl;
}
//測試用例:
int main(){
CStack<int> s;
s.Cpush(1);
s.Cpush(2);
s.Cpush(3);
s.Cpush(4);
s.Cpush(5);
s.Cpush(6);
s.show();
cout<<"出棧元素:"<<s.Cpop()<<endl;
cout<<"出棧元素:"<<s.Cpop()<<endl;
cout<<"出棧元素:"<<s.Cpop()<<endl;
s.Cpush(7);
cout<<"出棧元素:"<<s.Cpop()<<endl;
s.Cpush(8);
s.show();
}
/*輸出結果:
隊列1的元素大小:0
隊列2的元素大小:6
出棧元素:6
出棧元素:5
出棧元素:4
出棧元素:7
隊列1的元素大小:0
隊列2的元素大小:4
*/
//可見已經實現棧後進先出的特點!!
3.重溫斐波那契數列
//使用一般的遞歸實現
int fibonacci(int n){
if(n==0)
return 0;
if(n==1)
return 1;
if(n>1)
return fibonacci(n-1)+fibonacci(n-2);
}
//使用尾遞歸實現
long long fibonacci_trail(long long n,long long firstRes,long long secondRes){
if(n<0)
return -1;
if(n==0)
return 0;
if(n==1)
return 1;
if(n==2)
return firstRes+secondRes;
return fibonacci_trail(n-1,secondRes,firstRes+secondRes);
}
//解決實際問題
//青蛙跳臺階:青蛙可以一次跳1個臺階,也可以一次跳2個臺階,現在n級臺階公有多少種跳法
//對於1級臺階,只有一種跳法,對於2級臺階,有2種跳法,對於n>2級臺階,第一次跳1階,剩下共f(n-1)
//第一次跳2階,剩下共f(n-2)種跳法,所以一共f(n-1)+f(n-2)種跳法
//可以發現,青蛙跳臺階就是求斐波那契數列的問題