[数据结构] 二、栈和队列

目录

一、栈和队列的思维导图

二、栈和队列的基本概念

1、栈的基本概念

2、队列的基本概念

三、栈的结构体定义和基本操作

1、顺序栈

2、链栈

四、队列的结构体定义和基本操作

1、顺序队

2、链队


、栈和队列的思维导图

 

栈(Stack)是一个先进后出(First In Last out,FILO)的线性表,它要求只在一端进行删除和插入操作。

队列(queue)是一种先进先出(First In First Out,FIFO)的线性表,它只允许在一端进行插入操作,在另一端进行删除操作。


二、栈和队列的基本概念

1、栈的基本概念

(1)栈的定义

栈(Stack)是一种只能在一端进行插入或删除操作的线性表。其中允许进行插入和删除操作的一端称为栈顶(Top)。栈顶由一个称为栈顶指针的位置指示器(顺序栈→记录元素所在数组的位置、链栈→记录栈顶元素所在节点地址的指针)来指示,它是动态变化的。表的另一端称为栈底,栈底固定不变。栈的插入和删除操作称为入栈出栈

(2)栈的特点:先进后出(First In Last out,FILO)——类比手枪弹夹。

(3)栈的存储结构

栈依照存储结构分为:顺序栈和链式栈,分别用顺序表和带头节点的单链式表来存储。

(4)栈的数学性质

当n个元素以某种顺序进栈,并且在任意时刻出栈(FILO),则所获得的元素排列数目N满足:

2、队列的基本概念

(1)队列的定义

队列(queue)简称队,是一种先进先出(First In First Out,FIFO)的线性表,它只允许在一端进行插入操作,而在另一端进行删除操作。可以插入的一端称为队尾(Rear),另一端称为队头(Front)。向列表中插入新的元素称为进队,新元素进队之后就成为新的队尾元素;从队列中删除元素称为出队,元素出队后,其后记元素就成为新的队头元素。

(2)队列的特点:先进先出(First In First Out,FIFO)——类比火车开过隧道。

(3)队列的存储结构:队列依照存储结构分为:顺序队和链式队,分别用环形数组和单链表来存储。


三、栈的结构体定义和基本操作

1、顺序栈

说明:顺序栈 st 的两个特殊状态和两个操作

st.top == -1;          //栈空状态
st.top == maxSize-1    //栈满状态

++(st.top);
st.data[st.top] = x;   //进栈操作

x = st.data[st.top];
--(st.top);            //出栈操作

(1)顺序栈的结构体定义:

typedef struct{
    int  data[maxSize];   //存放栈中元素,maxSize是已定义的常量
    int  top;           //栈顶指针(顺序栈这里实际是一个指示器,存放栈顶元素所在数组位置的标号)
}SqStack;             //顺序栈的类型定义

(2)顺序栈的初始化:初始化一个栈,只需要将栈顶指针设置为 -1

void initStack(SqStack  &st){    //初始化栈
    st.top = -1;                 //只需将栈顶指针设置为 -1
}

(3)判断栈空:栈 st 为空的时候返回1,否则返回 0

int isEmpty(SqStack st){
    if(st.top == -1)
        return  1;
    else
        return  0;
}

(4)进栈操作:栈满不能进栈,若栈未满,先移动栈顶指针,然后将进栈元素赋值进去

int push(SqStack &st,int x){
    if(st.top == maxSize-1)    //判断栈是否满
        return  0;
    ++(st.top);                //先移动指针,再进栈
    st.data[st.top] = x;
        return  1;
}

(5)出栈操作:栈空不能出栈,若栈未空,先取出元素,再移动栈顶指针

int pop(SqStack &st,int &x){
    if(st.top == -1)            //判断栈是否为空
        return  0;
    x = st.data[st.top];        //将栈顶元素取出
    --(st.top);
    return  1;
}

2、链栈

说明:链栈的两个特殊状态和两个操作

lst->next == NULL;    //栈空状态
//假设不受内存限制,则不存在栈满的状态

p->next = lst->next;      //进栈元素由p指针所指
lst->next = p;            //进栈操作——类比单链表的头插法

p = lst->next;             //出栈元素由p指针所指
x = p->data;
lst->next = p->next;
free(p);                   //出栈操作——类比单链表的删除操作

(1)链栈的结构体定义:

typedef struct LNode{
    int  data;           //数据域
    struct LNode *next;  //指针域
}LNode;                  //链栈类型定义

(2)链栈的初始化:需要声明一个头节点(相当于栈顶指针),将其指针域赋值为 null

void initStack(LNode *&lst){                //lst要改变,用引用型
    lst = (LNode*)malloc(sizeof(LNode));    //制造一个头节点
    lst->next = NULL;
}

(3)判断栈空:头节点指针域为空则表示此时栈为空

int isEmpty(LNode *lst){     //指向头节点的指针lst
    if(lst->next == NULL)    //判断头节点的指针与是否为空
        return  1;
    else
        return  0;
}

(4)进栈操作:先为进栈元素申请节点空间,再将新节点做进栈插入操作

void push(LNode *lst, int x){
    LNode  *p;
    p = (LNode*)malloc(sizeof(LNode));    //为进栈元素申请节点空间
    p->next = NULL;                       //将新节点的指针域赋值为null
    
    p->data = x;
    p->next = lst->next;        //相当于链表的头插法
    lst->next = p;
    
}

(5)出栈操作:若栈空则不能出栈,若栈非空,再做出栈操作

int pop(LNode *lst,int &x){
    LNode  *p;
    if(lst->next == NULL)        //判断栈是否为空
        return  0;
    
    p = lst->next;                //假设p指向要出栈的元素
    x = p->data;                  //出栈操作,类比单链表的删除操作
    lst->next = p->next;
    free(p);
    return  1;
}

四、队列的结构体定义和基本操作

1、顺序队

说明:在顺序队中,通常让队尾指针rear 指向刚进队的元素位置,让队首指针ront 指向刚出队的元素位置。因此,元素进队的时候,rear要向后移动;元素出队的时候,front也要向后移动。这样经过一系列的出队和进队操作以后,两个指针最终会达到数组末端maxSize-1处。虽然队中已经没有元素,但仍然无法让元素进队,这就是所谓的“假溢出”。要解决这个问题,可以把数组弄成一环,让rear和front沿着环走,这样就永远不会出现两者来到数组尽头无法继续往下走的情况,这样就产生了循环队列循环队列是改进的顺序队列。下面是循环队列的两个特殊状态和两个操作

qu.rear == qu.front;                //队空状态
(qu.rear+1)%maxSize == qu.front;    //队满状态

qu.rear = (qu.rear+1)%maxSize;
qu.data[qu.rear] = x;                //进队操作(移动队尾指针)

qu.front = (qu.front+1)%maxSize;
x = qu.data[qu.front];                //出队操作(移动队头指针)

(1)顺序队列的结构体定义:

typedef struct{
    int  data[maxSize];
    int  front;            //队首指针
    int  rear;             //队尾指针
}SqQueue;                  //顺序队类型定义

(2)顺序队的初始化:队首和队尾指针重合,并且指向 0

void initQueue(SqQueue  &qu){
    qu.front = qu.rear = 0;    //队首和队尾指针重合,并且指向 0
} 

(3)判断队空:不论队首、队尾指针指向数组中哪个位置只要两者重合,即为队空

int isQueueEmpty(SqQueue  qu){
    if(qu.front == qu.rear)    //不论队首、队尾指针指向数组中哪个位置
        return  1;             //只要两者重合,即为队空
    else
        return  0;
}

(4)进队操作:队满不能进队,若队未满,先移动队尾指针,然后将进队元素赋值进去

int enterQueue(SqQueue &qu,int x){
    if((qu.rear+1)%maxSize == qu.front)    //判断队列是否满
        return  0;
    qu.rear = (qu.rear+1)%maxSize;         //若未满,则先移动指针
    qu.data[qu.rear] = x;                  //再存入元素
    return  1;
}

(5)出队操作:队空不能出队,若队列未空,先取出元素,再移动队首指针

int deQueue(SqQueue &qu,int &x){
    if(qu.front == qu.rear)        //判断当前队列是否为空
        return  0;
    
    qu.front = (qu.front+1)%maxSize;      //若队不空,先移动指针
    x = qu.data[qu.front];                //再取出元素
    return  1;
}

2、链队

说明:链队就是从采用链式存储队列,用单链表实现。下面是链队的两个特殊状态和两个操作

lqu->rear == NULL;
lqu->front == NULL;        //两个条件均能判断链队为空
//假设不受内存限制,则不存在链队列满的状态

lqu->rear->next = p;
lqu->rear = p;            //进队操作(假设p指向进队元素)    队空为特殊状态需要单独考虑

p = lqu->front;
lqu->front = p->next;
x = p->data;
free(p);                  //出队操作(假设x存储出队元素)    队中只有一个元素的话需要单独考虑

(1)链队结构体定义:

typedef struct LiNode{
    int  data;             //数据域
    struct LiNode *front;  //队头指针
    struct LiNode *rear;   //队尾指针
}LiNode;                   //链队类型定义

(2)链队的初始化:开辟一个链队节点,将链队的前后指针都赋值为null

void initListQueue(LiQueue  *&lqu){
    lqu = (LiQueue*)malloc(sizeof(LiQueue));
    lqu->front = lqu->rear = NULL;
}

(3)判断队空:front 和 rear 任何一个为空都可以判断链队为空

int isQueueEmpty(LiQueue  *lqu){
    if(lqu->rear==NULL || Lqu->front==NULL)
        return  1;
    else
        return  0;
}

(4)入队操作:为入队的元素开辟内存空间,再将其做入队操作,若队为空则前后指针都指向它,若不为空则rear指向它

int isQueueEmpty(LiQueue *lqu, int x){
    QNode  *p;
    p = (QNode*)malloc(sizeof(QNode));
    p->data = x;
    p->next = NULL;
    
    if(lqu->rear == NULL)            //若队列为空,则新节点是队首节点也是队尾节点
        Lqu->front = lq->rear = p;
    else{
        lqu->rear->next = p;          //将新节点链接到队尾,rear指向它
        lqu->rear = p;
    }
}

(5)出队操作:如果队列中只有一个节点,则出队后将队列初始化即可,若不止一个,则进行出队操作

int  deQueue(LiQueue *lqu,int &x){
    QNode  *p;
    if(lqu->rear == NULL)                //判断此时的队列是否为空
        return  0;
    else
        p=lqu->front;
    if(lqu->front == lqu->rear)          //若队列只有一个节点,需要进行特殊操作
        lqu->front = lqu->rear = NULL;
    else
        lqu->front=lqu->front-next;
    x = p->data;
    free(p);
    return  1;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值