每日算法之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)种跳法
//可以发现,青蛙跳台阶就是求斐波那契数列的问题