数据结构4_栈
栈:
栈是一种先进先出(Last in First out,LIFO)的操作受限的线性表,只能在一端进出操作,可以进出的一端称为栈顶(top),另一端称为栈底(base)。栈也是以用顺序存储和链式存储两种方式存储;
1 顺序栈:
1.1 结构体定义:
动态分配:
typedef struct SqStack{
ElemType *base;//栈底指针
ElemType *top;//栈顶指针
}SqStack;
静态分配:
typedef struct SqStack{
ElemType data[Maxsize];//用数组分配固定内存空间
int top;
}SqStack;
1.2 基本操作:
1.2.1 顺序栈初始化:
/*分配内存空间并使头尾指针重合*/
bool InitStack(SqStack &S){
S.base = new int[Maxsize];
if(!S.base){
return false;
}
S.top = S.base;
return true;
}
1.2.2 入栈:
/*入栈时先入元素到top所指位置然后top++*/
bool Push(SqStack &S, int e){
if(S.top - S.base == Maxsize){
return false;
}
*S.top++ = e;
return true;
}
1.2.3 出栈:
/*出栈是入栈的逆序*/
Elemtype Pop(Sqstack &S){
Elemtype e;
if(S.base == S.top) return -1;
e = *--S.top;
return e;
}
1.2.4 取栈顶元素:
/*与出栈相比,减少了top--的操作*/
Elemtype GetTop(Sqstack &S){
Elemtype e;
if(S.base == S.top) return -1;
e = *(S.top-1);
return e;
}
使用静态分配的栈操作与上大同小异;
2. 栈的链式存储:
2.1 结构体定义:
typedef struct Linknode{
ElemType data;
struct Linknode *next;
}Linknode,*LinkStack;
插入删除和链表类似,但是只能在栈顶操作,这里只介绍入栈,请类比自己写出出栈操作:
2.2 初始化和出栈:
/*初始化*/
bool InitStack(LinkStack &S){
S = NULL;
return true;
}
/*不带头结点的链栈入栈*/
bool Push(LinkStack &S, int e){
LinkStack p = new Linknode;
p -> data = e;
p -> next = S;
S = p;
return true;
}
/*带头结点的链栈入栈*/
bool Push(LinkStack &S, int e){
LinkStack p = new Linknode;
p -> data = e;
p -> next = S -> next;
S -> next = p; //与不带头节点的区别是S不存储元素,且指向实际栈顶
return true;
}
顺序栈和链栈在基本操作上都只需要常数时间,所以在时间效率上难分伯仲。在空间效率上,顺序栈需要预先分配固定长度的空间,有可能造成空间浪费或者溢出,但是链栈每次只分配一个结点的空间,所以不会出现溢出,但是每个结点需要额外的指针域,空间开销增大。因此,如果元素个数比较多,则选择链栈,反之选择顺序栈,但一般情况下顺序栈足以解决问题。
其次,栈的先进先出是人为规定的,而且我们的简单实现中没有实现从中间取出元素所对应的禁止操作,所以可以从中间取出元素,但是在使用一些语言封装好的数据结构时一般不允许操作中间元素。