顺序栈
顺序栈继承了虚拟栈类,并用数组存储栈的元素。顺序栈的实现,本质上是顺序表实现的简化。顺序栈以线性表的表尾作为栈顶,即当栈中有n个元素时把位置n-1作为栈顶,这样每次push或者pop操作的时间代价仅为θ(1)。
下面是顺序栈的实现:
template <class Elem>
class AStack : public Stack<Elem>
{
private:
int size; //栈的最大范围
int top; //栈顶元素 以及栈当前的大小
int *listArray; //存放栈的元素
enum { DefaultListSize = 50 }; //栈的默认最大范围
public:
AStack(int sz = DefaultListSize)
{
size = sz;
top = 0;
listArray = new Elem[sz];
}
~AStack() { delete [] listArray; }
// 清空栈内元素,把top设为0即可
void clear() { top = 0; }
// 入栈
bool push(const Elem& elem)
{
if (top == size) return false;
listArray[top++] = elem;
return true;
}
// 出栈
bool pop(Elem& elem)
{
if (top == 0) return false;
elem = listArray[--top];
return true;
}
// 获取栈顶元素的值
bool topValue(Elem& elem) const
{
if (top == 0) return false;
elem = listArray[top - 1];
return true;
}
// 获取栈的元素个数
int length() const
{
return top;
}
};
链式栈
链式栈的实现是对链表实现的简化。其元素只能在表头进行插入和删除。由于空栈或只有一个元素的栈都不需要特殊情形的结点,所以它不需要表头结点。
下面个提出了链式表的实现:
template <class Elem> class Node
{
public:
Node* next;
Elem element;
Node(const Elem elemval, Node* nextptr = nullptr)
{
element = elemval;
next = nextptr;
}
};
template <class Elem>
class LStack : public Stack<Elem>
{
private:
Node<Elem>* top; // 栈顶元素
int size; // 栈的元素个数
public:
LStack()
{
top = nullptr;
size = 0;
}
~LStack() { clear(); }
// 清空栈内的元素
void clear()
{
while (top != nullptr)
{
Node<Elem>* ntemp = top;
top = top->next;
delete ntemp;
}
size = 0;
}
// 入栈
bool push(const Elem& elem)
{
// 先创建一个新结点指向top,然后再把这个结点的地址附给top
top = new Node<Elem>(elem, top);
++size;
return true;
}
// 出栈
bool pop(Elem& elem)
{
if (size == 0) return false;
elem = top->element;
// 定义一个指针指向要出栈的元素
Node<Elem>* ntemp = top;
// 栈顶指向前一个元素的位置
top = top->next;
delete ntemp;
--size;
return true;
}
// 获取栈顶元素的值
bool topValue(Elem& elem) const
{
if (size == 0) return false;
elem = top->element;
return true;
}
// 获取栈的元素个数
int length() const
{
return size;
}
};
顺序栈和链式栈的比较
实现顺序栈和链式栈的所有操作都只需要常数时间,所以从时间效率上看,谁也不占名校的优势。另一个比较的基准是所需要的全部空间。
初始时顺序栈必须说明一个固定的长度,当栈不够满时,一些空间将浪费掉。链式栈的长度可变,但是对于每个元素都需要一个链接域,从而产生了结构性开销。
当需要实现多个栈时,可充分利用顺序表单向延伸的特性。因此,可以使用一个数组来存储两个栈,每个栈从各自的端点向中间延伸,如下图,这样浪费的空间会减少。但是,只有两个栈的空间需求有相反的关系时这种方法才奏效。也就是说,最好是一个栈增长时另一个栈缩短。当需要从一个栈中取出元素放入另一个栈时,这种方法非常有效。反之,如果两个栈同时增长,则数组中间的可用空间很快就会用完。