栈
8.1定义和描述
- 定义:栈(stack)是一种特殊的线性表,其插入(入栈、压栈)和删除(出栈、弹栈)操作都在表的同一端进行
- 栈顶
top
:允许插入和删除的一端 - 栈底
bottom
:另一端 - 可以使用任意一种线性表的描述方法
8.2抽象数据类型
ADT
抽象数据类型stack
{
实例
元素线性表,一端为栈底,另一端为栈顶
操作
empty();//栈为空时返回true,否则返回false
size();//返回栈中元素个数
top();//返回栈顶元素
pop();//删除栈顶元素
push(x);//将元素x压入栈
}
c++抽象类
template <class T>
class stack
{
public:
virtual ~stack(){}
//栈为空时返回true,否则返回false
virtual bool empty() const = 0;
//返回栈中元素个数
virtual int size()const = 0;
//返回栈顶元素
virtual T& top() = 0;
//删除栈顶元素
virtual void pop() = 0;
//将元素theElement压入栈Y
virtual void push(const T& theElement) = 0;
};
8.3数组描述
两种方法:
- 在
arrayList
类上派生得到数组描述的栈类derivedArrayStack
- 定制数组描述的栈类
arrayStack
8.3.1作为一个派生类实现
补:arrayList类
template<class T>
class arrayList:public linearList<T>
{
public:
//构造函数、复制构造函数、析构函数
arrayList(int initialCapacity = 10);
arrayList(const arrayList<T>&);
~arrayList(){delete[]element;}
//ADT方法
bool empty() const {return listSize == 0;}
int size() const {return listSize;}
T& get(int theIndex) const;
int indexOf(const T&theElement) const;
void erase(int theIndex);
void insert(int theIndex,const T&theElement);
void Output(ostream& out) const;
//其他方法
int capacity() const{return arrayLength;}
protected:
//若索引theIndex无效,则抛出异常
void checkIndex(int theIndex) const;
T *element;//存储线性表元素的一维数组
int arrayLength;//一维数组的容量
int listSize;//线性表的元素个数
};
派生出的数组栈类
同时继承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);}
};
评价:
- 优点:大大减少了编码两,程序的可靠性得到很大的提高
- 缺点:运行效率降低(push中不必要的下标检查和拷贝)
8.3.2 类arrayStack
- 栈顶元素:stack[stackTop]
- 栈底元素:stack[0]
类的声明
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();
void pop();
void push(const T& theElement);
private:
int stackTop;//当前栈顶
int arrayLength;//栈容量
T*stack;//元素数组
};
构造函数
template<class T>
arrayStack<T>::arrayStack(int initialCapacity = 10)
{
if(initialCapacity < 1)
{
ostringstream s;
s << "initialCapacity Must be > 0";
throw illegalParameterValue(s.str());
}
arrayLength = initialCapacity;
stack = new T[arrayLength];
stackTop = -1;
}
方法top
返回栈顶元素
template<class T>
T& arrayStack<T>::top()
{
if(stackTop == -1)
throw StackEmpty;
return stack[stackTop];
}
方法pop
删除栈顶元素
template<class T>
void arrayStack<T>::pop()
{
if(stackTop == -1)
throw StackEmpty;
//T的析构函数
stack[stackTop--].~T();
}
方法push
像栈顶压入一个元素
template<class T>
void arrayStack<T>::push(const T& theElement)
{
//如果栈已满,则容量加倍.
if(stackTop == arrayLength-1)
{
changeLength(stack, arrayLength, 2*arrayLength);
arrayLength *= 2;
}
//在栈顶插入元素
stack[++stackTop] = theElement;
}
在一个数组中描述两个栈
8.4链表描述
两种方法:
- 通过chain类派生得到链表描述的栈类
derivedLinkedStack
- 定制链表描述的栈类
linkedStacked类
- 选择链表的左端作为栈顶
8.4.1类derivedLinkedStack
类linkedStack
template<class T>
struct chainNode
{
T element;
chainNode<T>*next;
chainNode(){}
chainNode(const T&element)
{this->element = element;}
chainNode(const T&element,chainNode<T>*next)
{
this->element = element;
this->next = next;
}
};
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)
{
srackTop = new chainNode<T>(theElement,stackTop);
stackSize++;
}
private:
chainNode<T>*stackTop;//栈顶指针
int stackSize;//栈中元素个数
};
//析构函数,不断的删除栈顶元素
template<class T>
linkedStack<T>::~linkedStack()
{
while(stackTop != NULL)
{
//删除栈顶节点
chainNode<T>*nextNode = stackTop->next;
delete stackTop;
stackTop = nextNode;
}
}
//删除
template<class T>
void linkedStack<T>::pop()
{
if(stackSize == 0)
throw stackEmpty();
chainNode<T>* nextNode = stackTop->next;//复制栈顶的下一个元素
delete stackTop;//删除栈顶
stackTop = nextNode;//更新栈顶元素
stackSize--;
}
8.5应用
8.5.1括号匹配
8.5.2汉诺塔
//全局变量,tower【1:3】表示三个塔
arrayStack<int> tower[4];
//把n个碟子从塔x移动到塔y,可借助于塔z
void moveAndShow(int n,int x,int y,int z);
void towersOfHanoi(int n)
{
//函数moveAndShow的预处理程序
for(int d = n;d > 0;d--)//初始化
tower[1].push(d);//把碟子d放到塔1上
//把塔1上的n个碟子移动到塔2上,借助于塔3的帮助
moveAndShow(n,1,2,3);
}
void moveAndShow(int n, int x, int y, int z)
{
//把n个碟子从塔x移动到塔y,可借助于塔z
if(n>0)
{
moveAndShow(n-l,x,z,y);
int d = tower[x].top();//碟子编号
tower[x].pop();//从x中移走一个碟子
tower[y].push(d);//把这个碟子放到y上
ShowState();//显示塔的布局
moveAndShow(n-l,z,y,x);
}
}
8.5.3列车车厢重排
- 问题描述: