一个数组实现两个栈
用一个数组实现两个栈,有多种方法,但基本思路就下面三种方法,几种算法的实现区别不大,主要在与扩容时的条件,
第一种:以中间向两边压栈:
可以采用两个栈底分别在数组中间,栈顶向两边移动,当两个栈顶任意一个到达数组的两边时,数组扩容。
此种算法有两个扩容条件,二者满足其一便扩容:即只要有一边栈顶到达终端的时候就扩容。
第二种:两边向中间压栈
两个栈的栈底分别在数组的两边,压栈时栈顶向中间靠拢,当两个栈顶相遇时,数组扩容。
(在实际情形中,我们在使用拷贝构造和赋值时往往只在意是否拷贝到了自己想要的信息,并不在乎空间的开辟,而且用户根本也不知道内部是如何实现的,所以提高效率还是很有必要的)但我这里一开始并没有考虑那么多,我是直接将数组的内容直接拷贝上去。
第三种:分奇偶方式压栈
采用交叉索引的方法,两个栈分别拥有数组下标奇偶的空间,暂且把他们叫做奇数栈和偶数栈,把数组空间开辟为偶数(capacity),当偶数栈的栈顶到capacity-1或奇数栈的栈顶到达capaaity-2时数组扩容
同样此种算法扩容条件有两个,满足任意一个便扩容
条件1:偶数栈的栈顶到capacity-1
条件2:奇数栈的栈顶到达capaaity-2
分析:
第一种和第三种明显在扩容时考虑的情况比较复杂,条件更多一些。
空间使用率:第一种和第三种方法在其中一个栈压入比较多的数据而另外一个栈数据很少时,就存在非常大的空间浪费,但方案二就可以很好的避免这一情况,空间利用率比较高,而且这种方案在一个栈pop的空间另一个栈可以使用,可以在一些情况下减少开辟空间的次数(毕竟在c++中动态开辟空间还是很耗时的)
我用的是第二种方式:
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
//一个数组实现两个栈
//栈是一种数据结构,和内存中的堆栈并不是同一个
template<class T>
class ArrayStack //实际上是栈
{
public:
ArrayStack()
: _arr1(new T[1])
, _size(0)
, _capacity(1)
, _size2(0)
, _sz(_capacity - 1)
{
assert(_arr1);
_arr2 = &_arr1[_capacity - 1];
}
~ArrayStack()
{
if (!_arr1)
{
delete[] _arr1;
_size = 0;
_capacity = 0;
_size2 = 0;
_sz = 0;
}
}
ArrayStack(ArrayStack<T>& arr) //拷贝构造的仍然是一个数组
: _size(arr._size)
, _capacity(arr._capacity)
, _size2(arr._size2)
, _sz(arr._sz)
{
_arr1 = new T[_capacity];
for (int i = 0 ; i < _capacity; i++)//重头到尾一次遍历,最方便。
{
_arr1[i] = arr._arr1[i];
}
}
ArrayStack<T>& operator =(ArrayStack<T> arr)
{
swap(_arr1, arr._arr1);
swap(_arr2, arr._arr2);
swap(_size, arr._size);
swap(_size2, arr._size2);
swap(_capacity, arr._capacity);
return *this;
}
public:
void Arr1_Push_Back(T d)
{
Check_Cap(); //栈a1插入和栈a2插入数据前,判断两边插入数据是否相遇,是:开辟空间
_arr1[_size] = d;
_size++;
}
void Arr2_Push_Back(T d)
{
Check_Cap();
_arr1[_capacity - _size2-1] = d;
_size2++;
}
void Arr_DisPlay()
{
for (int i = 0; i < _capacity; i++)
{
cout << _arr1[i] << " ";
}
cout << endl;
}
void Arr1_DisPlay()
{
for (int i = 0; i < _size; i++)
{
cout << _arr1[i] << " ";
}
cout << endl;
}
void Arr2_DisPlay()
{
for (int j = _capacity - 1; j >_capacity - _size2 - 1; j--)
{
cout << _arr1[j] << " ";
}
cout << endl;
}
void Arr1_Pop_Back()
{
assert(_size > 0);
_size--;
}
void Arr2_Pop_Back()
{
assert(_size2 > 0);
_size2--;
}
private:
void Check_Cap()
{
if (&_arr1[_size] == &_arr1[_capacity - _size2 - 1])
{
int t_capacity = _capacity * 2 + 1;
int t = t_capacity;
int s = _size2;
T* tmp = new T[t_capacity];
for (int i = 0; i < _size; i++)
{
tmp[i] = _arr1[i];
}
while (s--)
{
tmp[t - 1] = _arr1[_capacity-1];
t--;
_capacity--;
}
delete[] _arr1;
_arr1 = tmp;
_capacity = t_capacity;
// _sz = _capacity-1; //同理,只要一扩容,_sz就会回到末端的位置,末端元素就会被覆盖
_arr2 = &_arr1[_capacity - 1];//只要一扩容就会末端元素在插入新的元素会被覆盖
}
}
protected:
T* _arr1;
T* _arr2;
int _size;
int _size2;
int _capacity;//容量是两栈共有
int _sz ;
};
#include"Array.h"
void test()
{
ArrayStack<int> as1;
as1.Arr1_Push_Back(1);
as1.Arr1_Push_Back(2);
as1.Arr2_Push_Back(6);
as1.Arr_DisPlay(); //整个数组两个栈
as1.Arr1_DisPlay();//前栈
as1.Arr2_Push_Back(5);
as1.Arr2_Push_Back(4);
as1.Arr2_DisPlay();//后栈
}
void test2()
{
ArrayStack<int> as1;
as1.Arr1_Push_Back(1);
as1.Arr1_Push_Back(2);
as1.Arr2_Push_Back(6);
as1.Arr1_Pop_Back();
as1.Arr_DisPlay(); //整个数组两个栈
as1.Arr1_DisPlay();
as1.Arr2_Push_Back(5);
as1.Arr2_Push_Back(4);
as1.Arr2_Pop_Back();
as1.Arr2_DisPlay();
as1.Arr_DisPlay(); //整个数组两个栈
cout << "---------------" << endl;
ArrayStack <int> as2;
as2 = as1;
as2.Arr_DisPlay();
as2.Arr2_DisPlay();
as2.Arr1_DisPlay();
cout << "------------------" << endl;
ArrayStack <int> as3(as1);
as3.Arr_DisPlay();
as3.Arr2_DisPlay();
as3.Arr1_DisPlay();
}
int main()
{
test2();
return 0;
}