数据结构(二)栈和队列

栈(stack):

  • 是限定仅在表位进行插入和删除操作的线性表

  • 允许插入的一段称为栈顶(top),另一端称为栈底(bottom),不包含任何数据元素的栈称为空栈

  • 栈又被称为是后进先出的线性表,简称LIFO结构

  • 栈的插入操作叫做进栈 push 也称压栈,入栈

  • 栈的删除操作叫做出栈 pop 也称弹栈

  • 栈的抽象数据类型

  • ADT 栈 stack
    Data 同线性表,元素具有相同的类型,相邻元素具有前驱和后继关系
    Operation
        	InitStack(*S):初始化操作,建立一个空栈
        	DestoryStack(*S):若栈存在,则销毁它
        	ClearStack(*S):将栈清空
        	StackEmpty(*S):若栈为空返回true,否则返回false
        	GetTop(S,*e):若栈存在且非空,用e返回S的栈顶元素
        	Push(*S,e):若栈S存在,插入新元素e到栈S中并成为栈顶元素
        	Pop(*S,*e):删除栈S中栈顶元素,并用e返回其值
        	StackLength(S):返回栈S的元素个数
    endADT
    
    typedef int SElemType;
    typedef struct 
    {
        SelemType data[MAXSIZE];
        int top;
    }SqStack;
    
    Status Push(SqStack *S,SElemType e)
    {
        if(S->top == MAXSIZE-1)
        {
            return ERROR;
        }
        S->top++;
        S->data[S->top];
        return OK;
    }
    
    Status Pop(SqStack *S,SElemType *e)
    {
        if(S->top == -1)
        {
            return ERROR;
        }
        *e = s->data[S->top];
        S->top--;
        return OK;
    }
    

    两栈共享空间(前提是两栈的数据类型相同)

    结构代码如下

    typedef struct
    {
        SElemType data[MAXSIZE];
        int top1;
        int top2;
    }SqDoubleStack;
    

    push操作

    Status Push(SqDoubleStack *S,SElemType e,int stackNumber)
    {
        if(S->top1+1 == S->top2)
        {
            return ERROR;
        }
        if(StackNumber == 1)
        {
            S->data[++S->top1]=e;
        }
        if(StackNumber == 2)
        {
            S->data[--S->top2]=e;
        }
        return OK;
    }
    

    pop操作

    Status Pop(SqDoubleStack *S,SElemType *e,int stackNumber)
    {
        if(stackNumber == 1)
        {
            if(S->top == -1)
            {
                return ERROR;
            }
            *e=S->data[S->top1--];
        }
        else if(stackNumber == 2)
        {
            if(S->top2 == MAXSIZE)
            {
                return ERROR;
            }
            *e=S->data[S->top2++];
        }
        return OK;
    }
    

    栈的链式存储结构(链栈)

    typedef struct StackNode
    {
        SElemType data;
        struct StackNode *next;
    }StackNode,*LinkStackPtr;
    
    typedef struct LinkStack
    {
        LinkStackPtr top;
        int count;
    }LinkStack;
    

    链栈的push操作

    Status Push(LinkStack *S,SElemType e)
    {
        LinkStackPtr s =(LinkStackPtr)malloc(sizeof(StackNode));
        s->data=e;
        s->next=S->top;
        s->top=s;
        s->count++;
        return OK;
    }
    

    链栈的pop出栈操作

    Status Pop(LinkStack *S,SElemType *e)
    {
        LinkStackPtr p;
        if(StackEmpty(*S))
        {
            return ERROR;
        }
        *e = S->top->data;
        p=S->top;
        S->top=S->top->next;
        free(p);
        S->count--;
        return OK;
    }
    

若栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些

队列

队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表

队列是一种先进先出(FIFO),允许插入的一段称为队尾,允许删除的一端称为队头

ADT 队列
Data 
    同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系
Operation
    InitQueue(*Q):初始化操作,建立一个空队列Q
    DestoryQueue(*Q):若队列Q存在,则销毁它
    ClearQueue(*Q):将队列Q清空
    QueueEmpty(Q):若队列Q为空,返回true,否则返回false
    GetHead(Q,*e):若队列Q存在且非空,用e返回队列Q的队头元素
    EnQueue(*Q,e):若队列Q存在,插入新元素e到队列Q中并成为队尾元素
    DeQueue(*Q,*e):删除队列Q中队头元素,并用e返回其值
    QueueLength(Q):返回队列Q的元素个数
endADT

指针front指向队头元素

指针rear指向队尾元素的下一个位置

队列的最大尺寸为QueueSize

循环队列

队列的头尾相接的顺序存储结构称为循环队列,rear指针指向队尾时,若再添加元素,rear指针从头开始

队列满的条件是:(rear+1)%QueueSize == front

通用的计算队列长度公式为:(rear-front+QueueSize)%QueueSize

//循环队列的顺序存储结构实现代码
typedef int QElemType;
typedef struct
{
    QElemType data[MAXSIZE];
    int front;		/*头指针*/
    int rear;		/*尾指针,若队列不空,指向队列尾元素的下一个位置*/
}SqQueue;
//循环队列的初始化
Status InitQueue(SqQueue *Q)
{
    Q->front=0;
    Q->rear=0;
    return OK;
}
//返回Q的元素个数,也就是队列的当前长度
int QueueLength(SqQueue Q)
{
    return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
//循环队列的入队列操作代码
Status EnQueue(SqQueue *Q,QElemType e)
{
    if((Q->rear+1)%MAXSIZE == Q->front)	//队列满的判断
    {
        return ERROR;		
    }
    Q->data[Q->rear]=e;		//rear指针向后移动一个位置
    Q->rear = (Q->rear+1)%MAXSIZE;	//若到最后则转向数组头部
    
    return OK;
}
//循环队列出队列操作代码
Status DeQueue(SqQueue *Q,QElemType *e)
{
    if(Q->front == Q->rear)		//队列空的判断
    {
        return ERROR;
    }
    *e=Q->data[Q->front];		//将队头元素赋值给e
    Q->front=(Q->front+1)%MAXSIZE;		/*front指针向后移动一个位置,若到最后则转到数组头部*/
    
    return OK;
}

队列的链式存储结构及实现

队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列

front指针指向头结点

rear指针指向终端结点

空队列时front和rear都指向头结点

链队列的结构

typedef int QElemType;
typedef struct QNode	//结点结构
{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
    QueuePtr front,rear;		//队头、队尾指针
}LinkQueue;
//入队操作实现代码
Status EnQueue(LinkQueue *Q,QElemType e)
{
    QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
    if(!s)
    {
        exit(OVERFLOW);
    }
    S->data=e;
    S->next=NULL;
    Q->rear->next=s;
    Q->rear=s;
    return OK;  
}

出队操作

结点的后继结点出队,头结点的后继改为它后面的结点

若链表除头结点外只剩一个元素,则需要将rear指向头结点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值