1 概述
1.1 定义
栈是一种特殊的线性表,插入(入栈或压栈)和删除(出栈或弹栈)都在同一端进行。这一端成为栈顶,另一端为栈底。下图为栈的示意图。
1.2 抽象数据类型
用c++语言实现上图stack抽象类,代码如下:
template<class T>
class stack
{
public:
virtual ~stack() {}
virtual bool empty() const = 0;
// return true iff stack is empty
virtual int size() const = 0;
// return number of elements in stack
virtual T& top() = 0;
// return reference to the top element
virtual void pop() = 0;
// remove the top element
virtual void push(const T& theElement) = 0;
// insert theElement at the top of the stack
};
2 数组描述
2.1 由数组派生类实现
由于栈是特殊的线性表,所以由arrayList和stack派生得到。
template<class T>
class derivedArrayStack : private arrayList<T>,
public stack<T>
{
public:
derivedArrayStack(int initialCapacity = 10)
: arrayList<T>(initialCapacity) {}
bool empty() const
{
return arrayList<T>::empty();
}
int size() const
{
return arrayList<T>::size();
}
T& top()
{
if (arrayList<T>::empty())
throw stackEmpty();
return get(arrayList<T>::size() - 1);
}
void pop()
{
if (arrayList<T>::empty())
throw stackEmpty();
erase(arrayList<T>::size() - 1);
}
void push(const T & theElement)
{
insert(arrayList<T>::size(), theElement);
}
};
注:基类方法get和erase遇到空栈抛出illegalIndex形式,在栈中没有实际意义,可以通过try-catch代替对空栈的检查;LIFO原则可以在类derivedArrayStack的实例上贯彻执行
2.2 类arrayStack
利用上述派生方法得到一个栈类的时候,性能会有损失,例如插入一个元素时,push实际上调用的是arrayList的insert方法,会对下标进行检查,还要进行往回复制,这两个操作在栈中是不必要的。
所以直接从stack抽象类继承得到arrayStack类。
类声明:
template<class T>
class arrayStack : public stack<T>
{
public:
arrayStack(int initialCapacity = 10);
~arrayStack() { delete[] stack; }
bool empty() const { return stackTop == -1; }
int size() const
{
return stackTop + 1;
}
T& top()
{
if (stackTop == -1)
throw stackEmpty();
return stack[stackTop];
}
void pop()
{
if (stackTop == -1)
throw stackEmpty();
stack[stackTop--].~T(); // destructor for T
}
void push(const T & theElement);
private:
int stackTop; // current top of stack
int arrayLength; // stack capacity
T* stack; // element array
};
类实现:
template<class T>
arrayStack<T>::arrayStack(int initialCapacity)
{// Constructor.
if (initialCapacity < 1)
{
ostringstream s;
s << "Initial capacity = " << initialCapacity << " Must be > 0";
throw illegalParameterValue(s.str());
}
arrayLength = initialCapacity;
stack = new T[arrayLength];
stackTop = -1;
}
template<class T>
void arrayStack<T>::push(const T & theElement)
{// Add theElement to stack.
if (stackTop == arrayLength - 1)
{// no space, double capacity
changeLength1D(stack, arrayLength, 2 * arrayLength);
arrayLength *= 2;
}
// add at stack top
stack[++stackTop] = theElement;
}
3 链表描述
3.1 类derivedLinkedStack
此类从chain类派生,实现了stack抽象类。方法实现和derivedArrayStack基本相同,需要注意的是:方法get、insert、和erase的调用中作为索引的实参应改为0,使这些操作发生在链表的左端。声明如下:
template<class T>
class derivedLinkedStack : private chain<T>,
public stack<T>
{
public:
derivedLinkedStack(int initialCapacity = 10)
: chain<T> (initialCapacity) {}
bool empty() const
{return chain<T>::empty();}
int size() const
{return chain<T>::size();}
T& top()
{
if (chain<T>::empty())
throw stackEmpty();
return get(0);
}
void pop()
{
if (chain<T>::empty())
throw stackEmpty();
erase(0);
}
void push(const T& theElement)
{insert(0, theElement);}
};
3.1 类linkedStack
定制地开发链式描述的栈:linkedStack类。
template<class T>
class linkedStack : public stack<T>
{
public:
linkedStack(int initialCapacity = 10)
{stackTop = NULL; stackSize = 0;}
~linkedStack();
bool empty() const
{return stackSize == 0;}
int size() const
{return stackSize;}
T& top()
{
if (stackSize == 0)
throw stackEmpty();
return stackTop->element;
}
void pop();
void push(const T& theElement)
{
stackTop = new chainNode<T>(theElement, stackTop);
stackSize++;
}
private:
chainNode<T>* stackTop; // pointer to stack top
int stackSize; // number of elements in stack
};
4 应用
- 括号匹配
- 汉诺塔
- 列车车厢重拍
- 开关盒布线
- 离线等价类问题
- 迷宫老鼠