【数据结构】栈

一、栈的定义 

栈是一种只能在一段进行插入或删除操作的特殊线性表(类似于一个瓶子,只能从瓶口放入或倒出内容物)。表中允许进行插入、删除操作的一端称为栈顶(类似瓶口),另一端则称为栈底(瓶底)。栈顶的位置是动态的,由栈顶指针指示。当栈中没有元素时称为空栈,栈的插入操作称为进栈或入栈,删除操作称为退栈或出栈。

栈中元素逻辑关系与线性表的相同,栈可以采用与线性表相同的存储结构。

区别于普通线性表可以在任意位置进行插入删除操作的特点,栈的主要特点为“后进先出”,即后进栈的元素先出栈(靠近瓶口的内容物先被倒出)。因此栈也被称为后进先出表。需要注意的是,每次进栈的元素都放在原来的栈顶元素之前成为新的栈顶元素,每次出栈的元素都是当前的栈顶元素。

 

 栈的抽象数据类型定义如下:

ADT Stack
{
    D={ai|1<=i<=n,n>=0,ai为ELement类型}
    R={<ai,ai+1>|ai~ai+1∈D,i=1,...,n-1}

    InitStack(&s):初始化
    DestoryStack(&s):销毁栈
    StackEmpty(s):P判断栈是否为空
    Push(&s,e):进栈
    Pop(&s,&e):出栈
    GetTop(s,&e):获取栈顶元素
}

二、栈的顺序存储结构及其基本运算的实现

1、结构体定义

typedef struct 
{  
   ElemType data[MaxSize]; 
   int top;//栈顶指针
} SqStack;

注意 :

1.top总是指向栈顶元素,初始值为-1(即栈空时s->top==-1)

2.进栈时先top+1,然后将元素e放在栈顶指针处;出栈时先将指针top处的元素取出存放在e中,然后将top-1。

3.当top=MaxSize-1时栈满,不能再进栈(栈满时s->top==MaxSize-1)

 

2、顺序栈的基本运算

 (1)初始化栈

SqStack *InitSqStack
{
    SqStack*s=(SqStack*)malloc(sizeof(SqStack));
    s->top=-1;
    return s;
}

(2)销毁栈

void DestoryStack(Sqstack*s){
    free(s);
}

(3)判断栈是否为空

bool StackEmpty(SqStack*s)
{
    return s->top==-1;
}

(4)进栈

bool Push(SqStack*s,ELemType e)
{
    if(s->top==MaxSize-1)
    return false;
    s->top++;//先改变top所指位置
    s->data[s->top]=e;//再将数据e赋值给top所指位置
    return true;
}

(5)出栈

bool Pop(SqStack*s,ELemType *e)
{
    if(s->top==-1)
    return false;
    *e=s->data[s->top];
    s->top--;
    return true;  
}

(6)获取栈顶元素

bool GetTop(SqStack*s,ELemType *e)
{
    if(s->top==-1)
    return false;
    *e=s->data[s->top];
    return true;
}

三、栈的链式存储结构及其基本运算的实现

采用链表存储的栈称为链栈。链栈有多种,这里采用带头结点的单链表实现。

1.结构体定义

typedef struct linknode
{    ElenType data;
    struct linknode *next;
}LinkStNode;

注意:

1.栈空的条件:s->next==NULL

2.只有内存溢出时才出现栈满,故可以视为不存在栈满

3.元素进栈需要先建立一个结点用于存放元素(由p指向它),将结点p插入头结点之后

4.出栈操作为取出头结点(即栈顶)的data值并删除

2、链栈的基本运算

 (1)初始化栈

LinkStNode *InitSqStack
{
    LinkStNode*s=(LinkStNode*)malloc(sizeof(LinkStNode));
    s->next=NULL;
    return s;
}

(2)销毁栈

void DestoryStack(LinkStNode*s)
{
    LinkStNode *pre=s,*p=s->next;//pre指向头结点,p指向首节点
    while(p!=NULL)//循环到首节点p为空
    {
        free(pre);//释放pre结点
        pre=p;
        p=pre->next;//pre、p同步后移
    }
    free pre;//此时pre指向尾节点,释放其空间
}

(3)判断栈是否为空

bool StackEmpty(LinkStNode*s)
{
    return s->top==NULL;
}

(4)进栈

bool Push(LinkStNode*s,ELemType e)
{
    LinkStNode*p;
    p=(LinkStNode*)malloc(sizeof(LinkStnode));//新建结点p
    p->data=e;//存放元素e
    p->next=s->next;//将p结点插入作为首结点
    s->next=p;
    return true;
}

(5)出栈

bool Pop(LinkStNode*s,ELemType *e)
{
    LinkStNode*p;
    if(s->next==NULL)
    return false;
    p=s->next;//p指向首结点
    e=p->data;//另存首结点值
    s->next=p->next;用下一个结点覆盖首结点(删除当前首结点)
    free(p);
    return true;  
}

(6)获取栈顶元素

bool GetTop(LinkStNode*s,Elemtype*e)
{
    if(s->next==NULL)
    return false;
    *e=s->next->data;
    return true;
}

注意:用链表表示栈时,首结点才是栈顶,头结点进作为链表操作的统一接口是在链表的第一个有效元素结点之前附设的一个结点,它不是链表的有效数据结点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值