每日算法之4

每日算法之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)種跳法

//可以發現,青蛙跳臺階就是求斐波那契數列的問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章