1栈
栈是一种重要的线性结构。
它是线性表(顺序表、链表)的一种具体形式。也就是说,栈需要通过顺序表或者链表来实现。
(等价于栈用顺序存储和用链式存储,称为顺序栈和链栈。)
栈(stack)是一个后进先出(last in first out ,LIFO)的线性表,进出的一端称为栈顶(top),另一端称为栈底(base)。
1.1顺序栈
顺序栈需要两个指针,base指向栈底,top指向栈顶。
typedef struct SqStack{
ElemType *base; //栈顶指针
ElemType *top; //栈底指针
}SqStack; //typedef将结构体等价于类型名SqStack
//ElemType是元素的类型
这里属于栈的定义我们还需先定义一个最大的分配空间。(顺序结构都需先定义空间)
#define Maxsize 100; //空间数值需要根据实际预估确定
1.栈的初始
初始化一个空栈,动态分配Maxsize大小的空间,用S.top和S.base指向该空间的基地址。
bool InitStack(SqStack &S){
S.base=new int [MaxSize]; //分配一段最大容量为Maxsize的内存空间
if(!S.base) return false; //空间分配失败
S.top=S.base; //首地址等于末地址,此时空栈
return true;
}
2.入栈
1.前要判断是否达最大容量,若已达,则入栈失败;
2.否则就将元素添加到栈顶,栈顶指针向上移动一位(top++)。
bool Push(SqStack &S,int e){ //将元素e添加到栈顶
if(S.top-S.base == Maxsize) //判断是否栈满
return false;
*S.top+=e;
/*等价于
*S.top=e;
*S.top++;*/
return true;
}
3.出栈
1.出栈前判断是否栈空,若栈空,则出栈失败;
2.否则将栈顶元素暂存给栈外的一个变量,栈顶指针向下移动一位(top--)。
(注意:因为此时没有销毁出栈元素的空间,所以元素还在那个位置)
bool Pop(SqStack &S,int &e){
if(S.base==S.top) return false;
e=*S.top--;
/*等价于
e=*S.top;
*S.top--;*/
return true;
}
4.取栈顶元素
取栈顶元素只是把栈顶元素复制一份,对栈无实质性操作,栈内元素个数没有改变。而出栈是指将栈顶指针向下移动一个位置,栈内元素数量-1。
int GetTop(SqStack *S){
if(S.top!=S.base) //栈非空
return *(S.top -1);//返回栈顶元素的值
else return -1;
}
1.2链栈
定义:
1.链栈每个节点的地址是不连续的,只需要一个栈顶指针。
2.链栈的每个节点都包含两个域:数据域和指针域。
可以将链栈看作一个不带头节点的单链表,但只能在头部进行插入、删除、取值等操作。
链表的结构体定义:
typedef struct Snode{
ElemType data; //数据域
struct Snode *next; //指向下一个节点的指针
}Snode,*LinkStack;
1.链栈的初始化
采用跟链表一样的虚拟头节点,让栈顶指针为空。
bool InitStack(LinkStack &S){
S=NULL; //使头指针为空
return true;
}
2.入栈
入栈是将新元素节点压入栈顶。
链栈中栈顶为第一个节点,原第一个节点a,将新节点b插入到节点a前面,修改a指针指向新节点b即可。
bool Push(LinkStack &S,int e){
LinkStack P;
p = new Snode; //生成新节点
p -> data = e; //将e存入新节点数据域
p -> next = S; //将S的地址赋给新节点指针域
S = p; //修改栈顶指针为p,即p成为新的栈顶
return true;
3.出栈
出栈就是把栈顶元素删除,让栈顶指针指向下一个节点,并释放该节点内存。
bool Pop(LinkStack &S,int &e){ //删除S的栈顶元素,用e保存其值
LinkStack p;
if(S==NULL) return false; //栈空
e=S->data; //用e报存栈顶数据
p=S; //用p保存栈顶元素地址,用来释放
S=S->next; //修改栈顶指针,指向下一个节点(让下一个节点成为新栈顶)
delete p; //释放原栈顶的内存
return ture;
}
4.取栈顶元素
将栈顶元素复制一份。
int GetTop(LinkStack &S){ //返回S的栈顶元素,不修改栈顶指针
if(S!=NULL) return S->data; //栈非空,返回栈顶元素的值
else return -1;
}
两者对比
1.在时间效率上一样,顺序栈和链栈的所有基本操作都只需要常数时间;
2.在空间效率上,顺序栈需要要先分配固定长度的空间,有可能会造成空间浪费或溢出。
链栈每次只分配一个节点,除非没有内存,否则不会溢出,但每个节点都需一个指针域,结构性开销增加。
因此若元素个数变化较大,可采用链栈,反之采用顺序栈。
3.在实际应用中,顺序栈比链栈应用更广泛。
栈的操作
stack <Elemtype> st; //定义一个栈
Elemtype x;
st.push(x); //添加x到栈中
st.pop(); //删除栈的栈顶元素
st.push(x);
Elemtype y=st.top(); //将栈顶元素赋给y