1 什么是栈(stack)?
栈是限定仅在表尾进行插入和删除操作的线性表
2 有什么特点?
1)只允许在栈顶进行插入和删除操作
2)栈有两端,允许操作的称为栈顶,另一端称为栈底
3)允许空栈,即不含任何数据元素
4)栈是后进先出的线性表,LIFO(Last In First Out)结构
5)特殊的线性表
3 有哪些操作?
1)InitStack(*s):初始化操作,建立一个空栈S
2)DestoryStack(*s):若栈存在,则销毁它
3)ClearStack(*s):清空栈
4)StackEmpty(s):判断栈是否为空
5)GetTop(S,*e):若栈存在且非空,用e返回s栈的栈顶元素
6)Push(*s,e):若栈s存在,插入新元素e到栈s中并成为栈顶元素
7)Pop(*s,*e):删除栈s中的栈顶元素,并用e返回其值
8)StackLength(s):返回栈s的元素个数
4 有什么存储结构?
4.1 栈的顺序存储结构
一个简化的顺序存储线性表,以下定义一下栈的结构:
#define MAXSIZE 10;
#define OK 1;
#define EEROR 0;
typedef int Status;
typedef int ElemType;/*ElemTypel的类型可根据实际情况而定*/
typedef struct Stack{
ElemType data[MAXSIZE];
int top; //用于栈顶指针
} mStack;
4.1.1 进栈操作
1)步骤:
a 判断传入的栈是否满栈了,若是返回ERROR
b 将top加1,然后将data[top] 的值赋为插入值e,返回OK;
2)代码如下:
Status Push(Stack *s,ElemType e){
if( s->top == MAXSIZE-1){
reuturn ERROR;
}
s->top++;
s->data[s->top] = e;
return OK;
}
3)时间复杂度O(1);
4.1.2 出栈操作
1)步骤:
a 判断传入的栈是否为空,若是则返回ERROR
b 获取删除的值,并将top减1;
2)代码如下:
Status Pop(Stack *s,ElemType *e){
if( s->top == -1){
return ERROR;
}
*e = s->data[s->top];
s->top--;
return OK;
}
3)时间复杂度O(1);
4.1.3 两栈共享空间
注:假设一个栈长度为n,那么两栈总长为2n,初始化时top1指向0,top2指向2n-1
4.1.3.1 特点
a 具有一定的“动态扩容能力”,即当top2指向2n-1时,栈1则相当于拥有2n的长度。
b 满栈状态,top2 = top1+1;
定义一个两栈共享的栈结构:
typedef struct DoubleStack{
ElemType data[MAXSIZE];
int top1;
int top2;
}
4.1.3.2 进栈操作
1)步骤
a 判断当前栈是否满栈,若是则返回ERROR
b 判断要插入哪个栈,执行插入操作
2)代码如下:
Status Push(DoubleStack *s ,ElemType e ,int statckNumber){
if(s->top2 == s->top1+1){
return ERROR;
}
if(stackNumber == 1){
s->top1++;
s->data[s->top1] = e;
}else if(stackNumber == 2){
s->top2--;
s->data[s->top2] = e;
}
return OK;
}
4.1.3.3出栈操作
1)步骤
a 判断要删除哪个栈的元素,然后判断该栈是否空栈
b 若是则返回ERROR,否则执行删除操作
2)代码如下:
Status Pop(DoubleStack *s, ElemType *e,int stackNumber){
if(stackNumber == 1){
if(s->top1 == -1){
rerurn ERROR;
}else{
*e = s->data[s->top1];
s->top1--;
}
}else if(stackNumber == 2){
if(s->top2 == MAXSIZE){
return ERROR;
}else{
*e = s->data[s->top2];
s->top2++;
}
}
return OK;
}
注意:这样的数据结构适用于两个栈有彼消此长关系的情形,如股票的买入和卖出总量保持不变的,而且数据类型是相同的,否则意义不大
4.2 栈的链式存储结构
栈与链表相结合,栈的栈顶与链表的头指针相结合,定义一个链栈的结构:
typedef struct StackNode{
ElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct LinkStack{
LinkStackPtr top;
int count;
}
4.2.1 进栈操作
1)步骤
a 为要插入的元素开辟空间p
b 将e赋值给p->data
c 将p->next = s->top
d 将s->top = p,s->count加1,返回OK
2)代码如下:
Status Push(LinkStack *s,ElemType e){
LinkStackPtr p = (LinkStackPtr)malloc(sizeOf(StackNode));//开辟空间
p->data = e;//赋值
p->next = s->top;//把当前栈顶元素赋值给新结点的直接后继
s->top = p;头指针赋值为p
s->count++;
return OK;
}
4.2.2 出栈操作
1)步骤
a 判断当前栈是否为空栈,若是则返回ERROR
b 定义一个p = s->top,释放p
c 将s->top = s->top->next;
d 返回OK;
2)代码如下:
Status Pop(LinkStack *s, ElemType *e){
LinkStackPtr p;
if(s->top == NULL){
return ERROR;
}
p = s->top;
*e = p->data;
free(p);
s->top = s->top->next;
return OK;
}
5 相关问题
1)最先进栈的元素,是不是只能最后出栈?
答:不一定,栈对线性表的插入和删除的位置进行了限制,但没有对元素的进出时间进行限制,只需要保证每次出栈的元素是栈顶元素。
6 相关练习
1 用两个栈模拟一个队列
题目解析:http://blog.youkuaiyun.com/u011812294/article/details/49130465
2 输入两个整数序列,第一个表示栈的压入顺序,请判断第二序列是否为该栈的弹出序列,假设压入栈的所有数字均不相等。
3 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数,在该栈中,调用、push和pop的时间复杂度为O(1);
题目来自剑指offer,解析在下一篇博文中