栈
栈stack是限定仅在一段进行插入或删除操作的线性表。可以称栈为"LIFO"线性表(Last In First Out)。
习惯上称栈的可访问元素为栈顶元素(top),新的元素添加称为入栈(push),元素删除称为出栈(pop)。
栈的ADT
template <typename E> class Stack {
private:
void operator =(const Stack&) {} // Protect assignment
Stack(const Stack&) {} // Protect copy constructor
public:
Stack() {} // Default constructor
virtual ~Stack() {} // Base destructor
// Reinitialize the stack. The user is responsible for
// reclaiming the storage used by the stack elements.
virtual void clear() = 0;
// Push an element onto the top of the stack.
// it: The element being pushed onto the stack.
virtual void push(const E& it) = 0;
// Remove the element at the top of the stack.
// Return: The element at the top of the stack.
virtual E pop() = 0;
// Return: A copy of the top element.
virtual const E& topValue() const = 0;
// Return: The number of elements in the stack.
virtual int length() const = 0;
};
顺序栈
具有固定的长度,用size表示栈的大小,top表示当前所在的位置值,即栈顶。
为了提高效率,将顺序表中元素的最后一位设置为栈顶,这样每次的push,pop都在尾端进行,时间代价为Θ(1)。
而由于数组中,第几个位置的角标是比真实的第几位小1,所以,初始化top为-1。
在push操作时,先加入新值再top++;在pop操作时,先top--再删除栈顶。
顺序栈的实现:
template <typename E> class AStack: public Stack<E> {
private:
int maxSize; // Maximum size of stack
int top; // Index for top element
E *listArray; // Array holding stack elements
public:
AStack(int size =defaultSize) // Constructor
{ maxSize = size; top = 0; listArray = new E[size]; }
~AStack() { delete [] listArray; } // Destructor
void clear() { top = 0; } // Reinitialize
void push(const E& it) { // Put "it" on stack
Assert(top != maxSize, "Stack is full");
listArray[top++] = it;
}
E pop() { // Pop top element
Assert(top != 0, "Stack is empty");
return listArray[--top];
}
const E& topValue() const { // Return top element
Assert(top != 0, "Stack is empty");
return listArray[top-1];
}
int length() const { return top; } // Return length
};
链式栈
链式栈的实现是对链表实现的简化,如上文中所提到的可利用空间表,就是链式栈的一种实现。
由于链表的性质,显然要将栈顶top设为第一个结点。
链式栈的实现:
template <typename E> class LStack: public Stack<E> {
private:
Link<E>* top; // Pointer to first element
int size; // Number of elements
public:
LStack(int sz =defaultSize) // Constructor
{ top = NULL; size = 0; }
~LStack() { clear(); } // Destructor
void clear() { // Reinitialize
while (top != NULL) { // Delete link nodes
Link<E>* temp = top;
top = top->next;
delete temp;
}
size = 0;
}
void push(const E& it) { // Put "it" on stack
top = new Link<E>(it, top);
size++;
}
E pop() { // Remove "it" from stack
Assert(top != NULL, "Stack is empty");
E it = top->element;
Link<E>* ltemp = top->next;
delete top;
top = ltemp;
size--;
return it;
}
const E& topValue() const { // Return top value
Assert(top != 0, "Stack is empty");
return top->element;
}
int length() const { return size; } // Return length
};
对于两种实现方式的比较,操作的时间代价上相差无几,而空间代价则如上文所说,顺序栈的大小固定较死板,链式栈的结构性开销较大。