大话数据结构读书笔记 2 ---栈和队列

本文详细介绍了栈和队列这两种基本的数据结构。包括它们的概念、特性、应用场景以及各种存储方式,如顺序存储和链式存储,并针对每种存储方式提供了具体的实现方法。

栈和队列

栈又称为后进先出的线性表,简称LIFO结构
栈顶用top表示,当栈存在一个元素时,top=0;当为空栈时top=-1;

栈的顺序储存结构

栈的结构定义
typedef int SElemTyoe;//SElemType根据实际情况而定,这里假设为int
typedef struct
{
SElemType data[MAXSIZE];
int top;//用于栈顶指针
}SqStack;

栈的顺序储存结构-进栈

Status Push(SqStack *s, SElemType e)
{
    if(S->top==MAXSIZE-1)//栈满
{
    return ERROR;
}
S->top++;//栈顶指针增加1
S->data[S->top]=e;//将新插入的元素赋值给栈顶空间
return OK;

}

栈的顺序储存结构-出栈

Status Pop(SqStack *S,SElemType *e)
{
    if(S->top==-1)
    return ERROR;
    *e=S->data[S->top];//将要删除的栈顶元素赋值给e
    S->top--;
    return OK;
}

两栈共享空间

数组有两个端点,两个栈有两个栈底,一个栈的栈底为数组的始端,即下标为0处,另一个栈的栈底为数组的末端,即n-1处。两个栈如果增加元素,就是两端点向中间延伸

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

//插入元素,需要一个标志判断是栈1还是栈2

Status Push(SqDoubleStack *S, SElemType e,int stackNumber)
{
    if(S->top1+1==S->top2)//栈已满
        return ERROR;
    if(stackNumber==1)//栈1有元素进栈
    S->data[++S->top1]=e;//栈1则先top1+1后给数组元素赋值
    else if(stackNumber==2)//栈2有元素进栈
    S->data[--S->top2]=e;//栈2先top2-1后给数组元素赋值
    return OK;

}

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

}

栈的链式储存结构

链栈的空其实就是top=NULL
链栈的结构代码如下

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

栈的链式储存结构–进栈操作

Statusn Push(LinkStack *S, SElemType e)
{
LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
s->data=e;
s->next=S->top;
S->top=s;//将新的结点s赋值给栈顶指针
S->count++;
return OK;
}

栈的链式储存结构–出栈操作

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;
}

队列的定义

队列是只允许在一端进行插入操作,在另一端进行删除操作的线性表。是一种先进先出的的线性表,简称FIFO

循环队列的定义

循环队列

队列顺序存储的不足之处就是插入和删除数据时需要移动元素,还容易发生假溢出(数组空间有多余的,但队列队尾已经超出数组最大位置,称为假溢出)
队列有两个指针,front指向队头元素,rear指向队尾元素的下一个位置。
把队列的头尾相接的顺序储存结构称为循环队列。
我们采取当队列为空时就是front==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;
}

返回队列的长度
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;
    Q->rear=(Q->rear+1)%MAXSZIE //rear向后移动一位,若到最后则跳转到数组头部
    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;//把当前的s设置为队尾结点,rear指向s
    return OK;

}

队列的链式储存结构—出队列

Status DeQueue(LinkQueue *e,QElemtype *e)
{ 
    QueuePtr p;
    if(Q->front==Q->rear)//队列为空
        return ERROR;
    p=Q->front->next;//先将欲删除的结点保存下来
    *e=p->data;
    Q->front->next=p->next;//重新给头结点的后继赋值
    if(Q->rear==p)//如果对头是队尾,即删除后便成为空队列此时需要将rear指向头结点
        Q->rear=Q->front;
    free(p);
    return OK;
}

栈和队列总结

栈和队列都可以用线性表的顺序储存结构来实现
对于栈如果两栈的数据类型相同,则可以用数组的两端作为栈底共享空间的方法,最大程度利用数组的空间。
对于队列,循环队列使得队头和队尾可以在数组中循环变化,避免了插入和删除时需要移动数据,时间复杂度由O(n)减小到O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值