您的位置:首页 > 其它

一个数组实现两个栈

2016-04-13 12:39 1361 查看

一个数组实现两个栈

栈(stack),是限定在表尾进行插入或删除操作的线性表,对栈来说,表尾端称为栈顶,表头称为栈底。
实现栈首先应该对栈中数据元素和栈顶指针的关系有清楚的认识
栈顶指针和栈中元素的关系

压栈

用一个数组实现两个栈,有多种方法,但基本思路就下面三种方法,下面我们分别介绍下各种算法,几种算法的实现区别不大,主要在与扩容时的条件,下面我们主要侧重于几种算法的扩容
(1)、
我们可以采用两个栈底分别在数组中间,栈顶向两边移动,当两个栈顶任意一个到达数组的两边时,数组扩容。



此种算法有两个扩容条件,二者满足其一便扩容:

条件1:




条件2:




(2)、
两个栈的栈底分别在数组的两边,压栈时栈顶向中间靠拢,当两个栈顶相遇时,数组扩容。








在代码的实现时我们决定在拷贝构造和赋值操作符的重载时采取只对有信息的部分进行开辟空间,从而节省了空间和时间。(在实际情形中,我们在使用拷贝构造和赋值时往往只在意是否拷贝到了自己想要的信息,并不在乎空间的开辟,而且用户根本也不知道内部是如何实现的,所以提高效率还是很有必要的)



为了节省空间,我们采取上述拷贝构造方式,只拷贝有信息的部分。
(3)、
采用交叉索引的方法,两个栈分别拥有数组下标奇偶的空间,我们暂且把他们叫做奇数栈和偶数栈,我们把数组空间开辟为偶数(capacity),当偶数栈的栈顶到capacity-1或奇数栈的栈顶到达capaaity-2时数组扩容




此种算法扩容条件有两个,满足任意一个便扩容

条件1:



条件2:




下面我们分析下这几种方法:
从代码的实现上,几种算法的难易程度相当,
我们分别从程序的效率、空间使用率以及可维护性几方面进行对比
效率:过上面对几种方法的介绍,在程序的效率方面几种方法区别不是非常大,但第一种和第三种明显在扩容时考虑的情况比较复杂,条件更多一些。

空间使用率:第一种和第三种方法在其中一个栈压入比较多的数据而另外一个栈数据很少时,就存在非常大的空间浪费,但方案二就可以很好的避免这一情况,空间利用率比较高,而且这种方案在一个栈pop的空间另一个栈可以使用,可以在一些情况下减少开辟空间的次数(毕竟在c++中动态开辟空间还是很耗时的)

综上
我们选择第二种方案。
//(博主现在才明白其实在编程的整个过程中,最重要的是对问题的理解以及对于各种算法的理解,在代码的实现上,我们不能一步而蹴,先把简单的实现,再逐步优化,不要一开始被最优解把自己绑架了,什么事情都有一个循序渐进的过程,我们在平时的学习中,就应该一层一层分析,直至最后得到我们认为的最优方案)(仅仅是个人学习这么久的感悟)

以下我们把方案二的代码简单的实现下

template<class T>
class TwoStack
{
public:
TwoStack()
:_a(0)
,_top1(0)
,_top2(0)
,_capacity(0)
{
}

~TwoStack()
{
if(_a != NULL)
{
delete [] _a;
}
}

/*TwoStack(const TwoStack<T>& ts)
:_a(new T[ts._capacity])
,_top1(ts._top1)
,_top2(ts._top2)
,_capacity(ts._capacity)
{
for(size_t i = 0; i< _capacity-1; i++)
{
_a[i] = ts._a[i];
}
}*/

TwoStack( const TwoStack<T>& ts)
:_a(new T[ ts._capacity -ts._top2 +ts._top1])//size+1
,_top1(ts._top1)
,_top2(_top1)
,_capacity( ts._capacity -ts._top2 +ts._top1)
{
size_t j = ts._capacity - 1;
for(size_t i = 0; i<=_top1; i++)
{
_a[i] = ts._a[i];
}
for(size_t i = _capacity-1; i >_top2; i--,j--)
{
_a[i] = ts._a[j];
}
}

TwoStack<T>& operator= (TwoStack<T> ts)
{
_top1 = ts._top1;
_top2 = ts._top2;
_capacity = ts._capacity;
swap(_a,ts._a);
return *this;
}

void Push(const T& x,int choice)
{
_CheckCapacity();
if(choice == 0)
{

_a[_top1++] = x;
}
if(choice ==1)
{
_a[_top2--] = x;
}
}

void Pop(int choice)
{
if(choice == 0)
{
assert(_top1 > 0);
_top1--;
}
if(choice == 1)
{
assert(_top2 <_capacity-1);
_top2++;
}
}

T& Top(int choice)
{
if(choice == 0)
{
assert(_top1 > 0);
return _a[_top1-1];
}
if(choice == 1)
{
assert(_top2 <_capacity-1);
return _a[_top2+1];
}
}

bool Empty(int choice)
{
if(choice == 0)
{
return _top1 == 0;
}
if(choice == 1)
{
return _top2 ==_capacity-1;
}
}

size_t Size(int choice)
{
if(choice == 0)
{
return _top1;
}
if(choice == 1)
{
return _capacity-1-_top2;
}
}
void Print()
{
cout << "栈0为:";
for(size_t i = 0; i<_top1; i++)
{
cout << _a[i] <<" ";
}
cout<<endl;
cout << "栈1为:";
for(size_t j = _capacity-1; j>_top2; --j)
{
cout << _a[j] << " ";
}
cout <<endl<<endl;
}
protected:
void _CheckCapacity()
{
if(_a == NULL)
{
_capacity = 3;
_a = new T[_capacity];
_top2 = _capacity - 1;//此时不要忘了给_top2赋值,构造时给的是0
return;
}
if(_top1 == _top2)
{
size_t j = 0;
size_t oldCapacity = _capacity;//记住原来的
_capacity = 2 * _capacity;
T* tmp = new T[_capacity];
for(size_t i = 0;i <_top1;i++)//正向拷贝
{
tmp[i] = _a[i];
}
for(size_t i = _capacity-1, j = oldCapacity-1; j >_top2; i--, j--)//反向拷贝
{
tmp[i] = _a[j];
}
delete [] _a;
_a = tmp;
_top2 = (_capacity-1) - (oldCapacity-1-_top2);// 最后一个下标-元素个数
}
}
protected:
T* _a;
size_t _top1;
size_t _top2;
size_t _capacity;
};

以下是测试代码
#include"test.h"

void Test()
{
TwoStack<int> ts1;
ts1.Push(1,0);
ts1.Push(2,0);
ts1.Push(3,0);
ts1.Push(4,0);

ts1.Push(5,1);
ts1.Push(6,1);
ts1.Push(7,1);
ts1.Push(8,1);

TwoStack<int> ts2(ts1);

TwoStack<int> ts3 ;
ts3 = ts1;

cout<<"ts1"<<endl;
cout<<"栈0:"<<endl;
cout << "ts1.Size(0):"<<ts1.Size(0) <<endl;
while( !ts1.Empty(0) )
{
cout<<ts1.Top(0)<<' ';
ts1.Pop(0);
}
cout<<endl<<"栈1:"<<endl;
cout << "ts1.Size(1):"<<ts1.Size(1) <<endl;
while( !ts1.Empty(1) )
{
cout<<ts1.Top(1)<<' ';
ts1.Pop(1);
}

cout<<endl<<endl<<"拷贝构造的ts2"<<endl;
ts2.Print();
cout<<"赋值后的ts3"<<endl;
ts3.Print();
}

int main()
{
Test();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  一个数组 两个栈