问题:
1. 实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值的操作)的时间复杂度为O(1)
2. 使用两个栈实现一个队列
3. 使用两个队列实现一个栈
4. 判断元素出栈、入栈顺序的合法性。如:入栈的序列(1, 2, 3, 4, 5),出栈序列为(4, 5, 3, 2, 1)是合法序列,入栈的序列(1, 2, 3, 4, 5),出栈序列为(1, 5, 3, 2, 4)是不合法序列
5. 一个数组实现两个栈
1、 因为栈的特点就是“先进后出,后进先出”,而且只能在栈顶进行操作,所以Push和Pop的时间复杂度就是O(1),要返回最小值的话,可以用一个数组(或栈)记录栈中前n项的最小值,以空间换时间,这样的话就能在O(1)内返回最小值了。
例:
template<typename T>
class Stack
{
public:
Stack()
:_ptr(NULL)
, _min(NULL)
, _size(0)
, _capacity(0){}
~Stack()
{
delete[] _ptr;
delete[] _min;
_ptr = NULL;
}
void Push(const T& data);
void Pop();
T& Top();
bool Empty();
size_t Size();
T Min();
void CheckCapacity();
protected:
T* _ptr;
T* _min;
int _size;
int _capacity;
};
template<typename T>
T& Stack<T>::Top()
{
assert(_size>=0);
return _ptr[_size - 1];
}
template<typename T>
bool Stack<T>::Empty()
{
if (_size == 0)
return true;
else
return false;
}
template<typename T>
size_t Stack<T>::Size()
{
return (size_t)_size;
}
template<typename T>
void Stack<T>::Push(const T& data)
{
CheckCapacity();
_ptr[_size] = data;
if (_size == 0)
{
_min[_size] = data;
}
else
{
if (data< _min[_size - 1])
{
_min[_size] =data;
}
else
{
_min[_size] =_min[_size-1];
}
}
_size += 1;
}
template<typename T>
void Stack<T>::Pop()
{
assert(_size >= 0);
--_size;
}
template<typename T>
T Stack<T>::Min()
{
assert(_size>=0);
return _min[_size-1];
}
template<typename T>
void Stack<T>::CheckCapacity()
{
if (_size >= _capacity)
{
int NewCapacity = _capacity * 2 + 3;
T* tmp1= new T[NewCapacity];
T* tmp2 = new T[NewCapacity];
for (int i = 0; i < _size; i++)
{
tmp1[i] = _ptr[i];
}
delete[] _ptr;
_ptr = tmp1;
for (int i = 0; i < _size; i++)
{
tmp2[i] = _min[i];
}
delete[] _min;
_min = tmp2;
_capacity = NewCapacity;
}
}
2、因为栈是后进先出,而队列是先进先出,所以我们在用两个栈实现一个队列的时候,就要用两个栈来回交换,是它能够满座先进先出的特点。
template<typename T>
class Queue
{
public:
void Push(const T& data);
void Pop();
T& Front();
T& Back();
bool Empty();
size_t Size();
protected:
stack<T> s1;
stack<T> s2;
};
template<typename T>
void Queue<T>::Push(const T& data)
{
s1.push(data);
}
template<typename T>
void Queue<T>::Pop()
{
assert(s1.size() >= 0);
while (s1.size()>1)
{
s2.push(s1.top());
s1.pop();
}
s1.pop();
while (!s2.empty())
{
s1.push(s2.top());
s2.pop();
}
}
template<typename T>
T& Queue<T>::Front()
{
assert(s1.size ()>= 0);
while (s1.size()>1)
{
s2.push(s1.top());
s1.pop();
}
T& ebp=s1.top();
while (!s2.empty())
{
s1.push(s2.top());
s2.pop();
}
return ebp;
}
template<typename T>
T& Queue<T>::Back()
{
return s1.top();
}
template<typename T>
bool Queue<T>::Empty()
{
return s1.empty();
}
template<typename T>
size_t Queue<T>::Size()
{
return s1.size();
}
优化:
用两个栈实现一个队列的时候,可以将一个将一个栈固定为入队序列栈,将另一个栈固定为出队序列栈,只要出队序列栈不为空,我们就一直从出队序栈中Pop数据(Pop完之后不用再将数据倒回到入队栈中)。但是注意在size和empty的时候,是两个栈都要同时判断,还有就是在返回队尾的时候有可能出现入队栈为空,出队栈不为空,这时候就需要将出队栈的元素再倒回到入队栈中。
template<typename T>
class Queue
{
public:
void Push(const T& data);
void Pop();
size_t Size();
bool Empty();
T& Front();
T& Back();
private:
stack<T> _s1; //_s1作为入队
stack<T> _s2; //_s2作为出队
};
template<typename T>
void Queue<T>::Push(const T& data)
{
_s1.push(data);
}
template<typename T>
void Queue<T>::Pop()
{
assert((_s1.size()+_s2.size())); //两个栈都为空,则队列已空
if (_s2.empty()) //如果_s2以空,则需要把_s1中的元素导入_s2中
{
while (!_s1.empty())
{
_s2.push(_s1.top());
_s1.pop();
}
}
_s2.pop();
}
template<typename T>
size_t Queue<T>::Size()
{
return (_s1.size() + _s2.size()); //返回两个栈的元素之和
}
template<typename T>
bool Queue<T>::Empty()
{
if (_s1.empty() && _s2.empty()) //如果两个栈都为空,则返回true
{
return true;
}
else
{
return false;
}
}
template<typename T>
T& Queue<T>::Front()
{
assert((_s1.size() + _s2.size())); //两个栈都为空,则队列已空
if (_s2.empty()) //如果_s2以空,则需要把_s1中的元素导入_s2中
{
while (!_s1.empty())
{
_s2.push(_s1.top());
_s1.pop();
}
}
return _s2.top();
}
template<typename T>
T& Queue<T>::Back()
{
assert((_s1.size() + _s2.size())); //两个栈都为空,则队列已空
if (_s1.empty()) //_s1为空,则要把_s2栈中元素导入_s1
{
while (!_s2.empty())
{
_s1.push(_s2.top());
_s2.pop();
}
}
return _s1.top();
}
3、同样的,因为只要用两个队列来回交换,使得能够先进后出就行。
template<typename T>
class Stack
{
public:
void Push(const T& data);
void Pop();
T& Top();
bool Empty();
size_t Size();
private:
queue<T> q1;
queue<T> q2;
};
template<typename T>
void Stack<T>::Push(const T& data)
{
q1.push(data);
}
template<typename T>
void Stack<T>::Pop()
{
assert(q1.size()>=0);
while (q1.size()>1)
{
q2.push(q1.front());
q1.pop();
}
q1.pop();
while (!q2.empty())
{
q1.push(q2.front());
q2.pop();
}
}
template<typename T>
T& Stack<T>::Top()
{
return q1.back();
}
template<typename T>
bool Stack<T>::Empty()
{
return q1.empty();
}
template<typename T>
size_t Stack<T>::Size()
{
return (size_t)q1.size();
}
优化:两个队列实现一个栈,用两个指针分别指向一个空队列和一个非空队列,向非空队列中插入元素(都为空的话随便插入哪一个队列),在抛出的时候需要将非空队列的元素导入到空队列中Pop完之后不必再倒回去(提高半效率)。
template<typename T>
class Stack
{
public:
void Push(const T& data);
void Pop();
T& Top();
size_t Size();
bool Empty();
private:
queue<T> _q1;
queue<T> _q2;
};
template<typename T>
void Stack<T>::Push(const T& data)
{
向不空的队列里面插入数据
if (!_q2.empty()) //如果q2不为空
{
_q2.push(data);
}
else
{
_q1.push(data);
}
}
template<typename T>
void Stack<T>::Pop()
{
assert((_q1.size()+_q2.size())); //两个队列不能同时为空
queue<T> *tmp1= NULL; //记录不空的队列
queue<T> *tmp2 = NULL; //记录空的队列
if (_q1.empty()) //如果_q1为空
{
tmp1 = &_q2;
tmp2 = &_q1;
}
else
{
tmp1 = &_q1;
tmp2 = &_q2;
}
while (tmp1->size() > 1)
{
tmp2->push(tmp1->front());
tmp1->pop();
}
tmp1->pop();
}
template<typename T>
T& Stack<T>::Top()
{
assert((_q1.size() + _q2.size())); //两个队列不能同时为空
queue<T> *tmp1 = NULL; //记录不空的队列
if (_q1.empty()) //如果_q1为空
{
tmp1 = &_q2;
}
else
{
tmp1 = &_q1;
}
return tmp1->back(); //返回不空的队列的尾部元素
}
template<typename T>
size_t Stack<T>::Size()
{
return (_q1.size() + _q2.size());
}
template<typename T>
bool Stack<T>::Empty()
{
return (_q1.empty() && _q2.empty());
}
template<typename T>
class StackLegality
{
public:
void SetInArray(const T& data); //输入入栈序列
void SetOutAaary(const T& data); //输入出栈序列
bool DecideLegality();
private:
stack<T> s;
vector<T> InArray;
vector<T> OutArray;
};
template<typename T>
void StackLegality<T>::SetInArray(const T& data) //输入入栈序列
{
InArray.push_back(data);
}
template<typename T>
void StackLegality<T>::SetOutAaary(const T& data) //输入出栈序列
{
OutArray.push_back(data);
}
template<typename T>
bool StackLegality<T>::DecideLegality()
{
if (InArray.size() != OutArray.size()) //如果入栈序列与出栈序列的个数不相等,则一定不合法
{
return false;
}
int sz = (int)InArray.size();
int j = 0;
int i = 0;
while (i<sz)
{
if(i<sz&&s.empty()) //如果栈为空,则需要入栈
{
s.push(InArray[i]);
i++;
}
while (i<sz&&s.top() != OutArray[j]) //如果栈顶元素与出栈序列不相等,则一直入栈
{
s.push(InArray[i]);
i++;
}
while (!s.empty() && s.top() == OutArray[j])
{
s.pop();
j++;
int i1 = i;
int j1 = j;
while (i1<sz)
{
if (i1<sz&&s.empty()) //如果栈为空,则需要入栈
{
s.push(InArray[i1]);
i1++;
}
while (i1<sz&&s.top() != OutArray[j1]) //如果栈顶元素与出栈序列不相等,则一直入栈
{
s.push(InArray[i1]);
i1++;
}
while (!s.empty() && s.top() == OutArray[j1])
{
s.pop();
j1++;
}
}
if (j1 == sz)
{
return true;
}
else
{
j--;
while ((int)s.size()>=i)
{
s.pop();
}
s.push(InArray[i-1]);
s.push(InArray[i]);
i++;
}
}
}
if (j == sz)
{
return true;
}
else
{
return false;
}
}
5、用一个数组实现两个栈这个问题有两种办法。一种是将数组按照奇偶顺序分成两部分,分别是奇数栈和偶数栈。另一种办法就是分别以数组的首部和尾部为栈底,实现一个栈。
例:
第一种:
template<typename T>
class DoubleStack
{
public:
DoubleStack()
:_array(NULL)
, _size(0)
, _capacity(0)
, _top1(0) //第一个栈的栈顶
, _top2(1){} //第二个栈的栈顶
~DoubleStack()
{
delete[] _array;
}
public:
void Push(const T& data,int flag=0);
void Pop(int flag=0);
T& Top(int flag=0);
size_t Size(int flag=0);
bool Empty(int flag=0);
private:
void CheckCapacity();
private:
T* _array;
int _top1; //第一个栈的栈顶
int _top2; //第二个栈的栈顶
int _size;
int _capacity;
};
template<typename T>
void DoubleStack<T>::CheckCapacity()
{
if (_size >= _capacity)
{
int NewCapacity = 2 * _capacity + 2;
T* tmp = new T[NewCapacity];
for (int i = 0; i < _size; i++)
{
tmp[i] = _array[i];
}
delete[] _array;
_array = tmp;
_capacity = NewCapacity;
}
}
template<typename T>
T& DoubleStack<T>::Top(int flag)
{
if (flag == 0)
{
assert(_top1>0);
return _array[_top1-2];
}
else
{
assert(_top2>1);
return _array[_top2 - 2];
}
}
template<typename T>
void DoubleStack<T>::Push(const T& data, int flag)
{
CheckCapacity();
if (flag == 0)
{
_array[_top1] = data;
_top1+= 2;
if (_top1 > _top2)
{
_size += 2;
}
}
else
{
_array[_top2] = data;
_top2 += 2;
if (_top1<_top2)
{
_size += 2;
}
}
}
template<typename T>
void DoubleStack<T>::Pop(int flag)
{
if (flag == 0)
{
assert(_top1>0);
_top1 -= 2;
if (_top1>_top2)
{
_size-= 2;
}
}
else
{
assert(_top2>1);
_top2 -= 2;
if (_top1<_top2)
{
_size -= 2;
}
}
}
template<typename T>
size_t DoubleStack<T>::Size(int flag)
{
if (flag ==0)
{
return (size_t)(_top1 / 2);
}
else
{
return (size_t)((_top2 - 1) / 2);
}
}
template<typename T>
bool DoubleStack<T>::Empty(int flag)
{
if (flag == 0)
{
return _top1 == 0;
}
else
{
return _top2 == 1;
}
}
第二种:
template<typename T>
class DoubleStack
{
public:
DoubleStack()
:_array(NULL)
, _capacity(0)
, _top1(0)
, _top2(0){}
~DoubleStack()
{
delete[] _array;
}
public:
void Push(const T& data,int flag = 0);
T& Top(int flag = 0);
void Pop(int flag = 0);
size_t Size(int flag=0);
bool Empty(int flag = 0);
private:
void CheckCapacity();
private:
T* _array;
int _capacity;
int _top1;
int _top2;
};
template<typename T>
void DoubleStack<T>::CheckCapacity()
{
if (_top1==_top2)
{
int NewCapacity = 2 *_capacity + 4;
T *tmp =new T[NewCapacity];
for (int i = 0; i < _top1; i++)
{
tmp[i] = _array[i];
}
int j = _capacity - 1;
for (int i = NewCapacity - 1; j>_top2; --i,--j)
{
tmp[i] = _array[j];
}
delete[] _array;
_array = tmp;
size_t count =0; //求出第二个栈的元素的个数
if (_capacity != 0)
{
count = _capacity - 1 - _top2;
}
_capacity = NewCapacity;
_top2 =_capacity-1-count; //改变_top2的值
cout << _capacity << endl;
}
}
template<typename T>
void DoubleStack<T>::Push(const T& data,int flag = 0)
{
CheckCapacity();
if (flag == 0)
{
_array[_top1++] = data;
}
else
{
_array[_top2--] = data;
}
}
template<typename T>
T& DoubleStack<T>::Top(int flag = 0)
{
if (flag == 0)
{
assert(_top1>0);
return _array[_top1 - 1];
}
else
{
assert(_top2<_capacity-1);
return _array[_top2+1];
}
}
template<typename T>
void DoubleStack<T>::Pop(int flag = 0)
{
if (flag == 0)
{
assert(_top1>0);
_top1--;
}
else
{
assert(_top2<_capacity - 1);
_top2++;
}
}
template<typename T>
size_t DoubleStack<T>::Size(int flag = 0)
{
if (flag == 0)
{
return (size_t)_top1;
}
else
{
return (size_t)(_capacity-1-_top2);
}
}
template<typename T>
bool DoubleStack<T>::Empty(int flag = 0)
{
if (flag == 0)
{
return _top1 == 0;
}
else
{
return _top2 == (_capacity - 1);
}
}