1.1 栈的基本概念
1)栈仅包括逻辑结构,不包括存储结构和对数据的运算,这些都是栈的实现时需要考虑的事
2)栈是只允许在一端进行插入或删除操作的线性表
3)栈遵循后进先出 Last In First Out,栈顶(Top)允许进行插入和删除,栈底(Bottom)固定不允许进行插入和删除
4)空栈是不含任何元素的空表
5)n个不同元素进栈,出栈元素不同排列的个数为,该公式被称为卡特兰数
1.2 栈的顺序存储结构
1)顺序栈的实现
采用顺序存储的栈为顺序栈,top指针为栈顶指针,在进行初始化时可以初始化为-1,也可以初始化为0,这取决于栈顶指针是如何设置的,如果将栈顶指针指向栈顶元素,则应该初始化为-1,如果将栈顶指针指向栈顶元素的下一个位置,或者说下次入栈元素存放的位置,就应该初始化为0。
#define MAXSIZE 50
typedef struct{
ElemType data[MAXSIZE]; //定义数组用作栈的数据域
int top; //栈顶指针,指针为-1栈空,指针为MAXSIZE-1占满,进栈时先移指针,出栈时后移指针
}SqStack;
2)顺序栈的基本运算
①初始化
void InitStack(SqStack &S){
S.top=-1; //初始化栈,将栈顶指针置为栈空条件
}
②判栈空
bool StackEmpty(SqStack &S){
if(S.top==-1)
return true; //判空,如果栈空返回true
return false;
}
③进栈
bool Push(SqStack &S, ElemType e){
if(S.top==MAXSIZE-1)
return false; //如果栈满,返回false
S.top++; //先让栈顶指针前进1
S.data[top]==e; //将元素存入栈
return true;
}
④出栈
bool Pop(SqStack &S, ElemType &e){
if(S.top==-1)
reutrn false; //如果空,返回false
e=S.data[S.top]; //将弹出的元素用e带回
S.top--; //将指针后退一位
return true;
}
⑤读栈顶元素
bool GetTop(SqStack &S, ElemType &e){
if(S.top==-1)
reutrn false; //如果空,返回false
e=S.data[S.top]; //将弹出的元素用e带回
return true; //读取栈顶元素不会弹出栈顶元素,所以不用移动指针
}
3)共享栈
因为栈底是固定的,所以让两个顺序栈共用一个数组,将两个栈的栈底分别固定在数组的左右两侧,两个栈分别向共享空间中间延伸,当两个栈的栈顶指针相邻时,共享栈栈满,即S1.top=S2.top-1,当两个栈的栈顶指针分别指向S1.top=-1,S2.top=MAXSIZE时,共享栈栈空
1.3 栈的链式存储结构
1)采用链式存储的栈称为链栈,它的优点是可以动态分配内存空间,不会出现栈满的情况,也便于多个栈共享存储空间
2)栈的链式存储首节点为栈顶,尾结点为栈底
3)链栈代码描述,因为栈限制了存取点,所以链栈其实并不具备很强的优势
typedef struct Linknode{
ElemType data; //链栈数据域
struct Linknode *next; //链栈的next指针
}StackNode //链栈结点
typedef struct{
StackNode *Lhead; //链栈栈顶指针
}LinkStack; //链栈本身,其中包含栈顶指针
1.4 重难点解析
1)对于固定第一个出栈元素(往往是入栈序列中的倒数第二个),求可能的出栈序列数量,此时,对于固定的元素之前的所有的元素其入栈顺序已经确定,所以出栈时它们也只能依次出栈,所以只需要考虑固