day06(数据结构)队列

队列 queue

1. 特性

队列是只允许在两端进行插入和删除操作的线性表,在队尾插入,在队头删除,插入的一段被称为“队尾”,删除的一端被称为“队头”。

队列包括:顺序队列(循环队列)、链式队列。

结构:先进先出FIFO

操作:创建、入列、出列、判空和判满。

注意:为了避免假溢出问题,即队列前面还有空闲,但是队尾已经出现越界,所以在实际使用队列时,为了使队列空间能重复使用,往往对队列的使用方法稍加改进,需要引入循环队列

循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。

2. 循环队列

逻辑结构:线性结构

存储结构:顺序存储

操作:创建、入列、出列、判空和判满。

入列:

出队:

求长度:

#include <stdio.h>
#include <stdlib.h>
#define N 5
typedef int datatype;
typedef struct sequeue //循环队列结构体
{
    datatype data[N]; //循环队列存数据的数组
    int front;        //队头元素下标
    int rear;         //队尾元素下标
} sequeue_t;

//创建一个空的队列
sequeue_t *createEmptySequeue()
{
    //开辟循环队列结构体大小空间
    sequeue_t *p = (sequeue_t *)malloc(sizeof(sequeue_t));
    if (NULL == p)
    {
        perror("p mallo err");
        return NULL;
    }
    //初始化结构体空间
    p->front = 0; //队头和队尾初始化为0
    p->rear = 0;
    return p;
}

//判断队列是否为满
int isFullSequeue(sequeue_t *p)
{
    //思想上,舍去数组上的一个存储位置,用于判断队列是否为满
    //先判断rear的下一个位置是否等于front
    return (p->rear + 1) % N == p->front;
}

//入列 data代表入列的数据
int inSequeue(sequeue_t *p, datatype data)
{
    //1.容错判断,入列前需要判断队列是否为满
    if (isFullSequeue(p))
    {
        printf("isFullSequeue !!\n");
        return -1;
    }
    //2. 将数据入列
    p->data[p->rear] = data;
    //3.队尾向后移动一个单位 (不能单纯的++,要利用取余法让下标循环)
    p->rear = (p->rear + 1) % N;
    return 0;
}
//判断队列是否为空
int isEmptySequeue(sequeue_t *p)
{
    return p->rear == p->front;
}
//出列
datatype outSequeue(sequeue_t *p)
{
    datatype temp; //临时保存下即将出列的数据
    //1.容错判断: 判空
    if (isEmptySequeue(p))
    {
        printf("isEmptySequeue !!\n");
        return -1;
    }
    //2. 将数据取出
    temp = p->data[p->front];
    //3. 将头向后移动一个单位
    p->front = (p->front + 1) % N;
    //4. 返回出队数据
    return temp;
}

//求队列的长度
int lengthSequeue(sequeue_t *p)
{
    //长度情况分为 rear >= front  和 rear < fron  //rear == front 就是空队列长度为0
    // if (p->rear >= p->front)
    //     return p->rear - p->front;
    // else //p->rear < p->front
    //     return p->rear - p->front + N;

    return (p->rear - p->front + N) % N;
}

int main(int argc, char const *argv[])
{
    sequeue_t *p = createEmptySequeue();
    for (int i = 0; i < 5; i++)
        inSequeue(p, i); //最后一次循环回报: isFullSequeue !!

    printf("len = %d\n", lengthSequeue(p)); //len=4

    while (!isEmptySequeue(p))
        printf("%d\n", outSequeue(p)); //0 1 2 3先进先出

    return 0;
}

循环队列,如果数组的元素个数为N,那么队列中最多能够存储的数据数的多少? N-1个  

为什么?

答:rear 后面 队尾,在插入的时候,插入之前需要先判断 rear+1,也就是他的下一个为位置是否 等于 front 来判断队列是否为满,会造成浪费一个存储位置。

3. 链式队列

逻辑结构:线性结构

存储结构:链式存储

操作:创空、入列、出列、判空

创建空队列:

入队:

出队:

#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node
{
    datatype data;
    struct node *next;
} node_t, *node_p;

typedef struct linkqueue //将队列的头尾指针封装成一个结构体
{
    node_p front; //相当于队列的头指针
    node_p rear;  //相当于队列的尾指针
} linkqueue_t, *linkqueue_p;

//创建一个空的队列,用有头链表。
linkqueue_p createEmptyLinkQueue()
{
    //1. 开辟队列结构体大小空间
    linkqueue_p p = (linkqueue_p)malloc(sizeof(linkqueue_t));
    if (NULL == p)
    {
        perror("p malloc er");
        return NULL;
    }
    //2. 初始化队列结构体, 让头尾指针都指向开辟的头节点
    p->front = p->rear = (node_p)malloc(sizeof(node_t));
    if (NULL == p->front)
    {
        perror("p->front malloc err");
        return NULL;
    }
    //3. 初始化头节点
    p->front->next = NULL;

    return p;
}

//入列 data代表入列的数据
int inLinkQueue(linkqueue_t *p, datatype data)
{
    // 新建节点,保存入队数据
    node_p pnew = (node_p)malloc(sizeof(node_t));
    if (NULL == pnew)
    {
        perror("pnew malloc err");
        return -1;
    }
    pnew->data = data;
    pnew->next = NULL;
    // 将新节点尾插到链表
    p->rear->next = pnew;
    // 移动尾指针到新节点
    p->rear = pnew;

    return 0;
}

//判断队列是否为空
int isEmptyLinkQueue(linkqueue_p p)
{
    return p->front == p->rear;
}

//出列
datatype outLinkQueue(linkqueue_p p)
{
    //判空
    if (isEmptyLinkQueue(p))
    {
        printf("outLinkQueue err\n");
        return -1;
    }
    //定义pdel保存当前头节点
    node_p pdel = p->front;
    //将头指针向后移动
    p->front = p->front->next;
    //释放pdel
    free(pdel);
    //将要出队数据返回
    return p->front->data;
}

//求队列长度
int lengthLinkQueue(linkqueue_p p)
{
    int len = 0;
    node_p h = p->front;

    //求长度,相当于遍历有头链表
    while (h->next != NULL)
    {
        h = h->next;
        len++;
    }
    return len;
}

int main(int argc, char const *argv[])
{
    linkqueue_p p = createEmptyLinkQueue();
    inLinkQueue(p, 1);
    inLinkQueue(p, 2);
    inLinkQueue(p, 3);
    inLinkQueue(p, 4);
    inLinkQueue(p, 5);
    // node_p p1 = p->front;
    // while (p1->next != NULL)
    // {
    //     p1 = p1->next;
    //     printf("%d ", p1->data);
    // }
    printf("len = %d\n", lengthLinkQueue(p));
    while (!isEmptyLinkQueue(p))
    {
        printf("%d\n", outLinkQueue(p)); //1 2 3 4 5
    }

    return 0;
}

思考:如何用两个栈实现一个队列的功能

思路:设两个栈,一个用于in一个用于out

实现入队: 如果in栈没满直接入栈,如果满了,出栈之后入out栈,这样先入栈的会在out栈的栈顶。

实现出列: 如果out栈不为空直接让数据出栈,如果为空则把in栈的数据依次出栈入out栈, 这样先入栈的数据会在out栈顶。然后再把数据出out栈,来实现出列功能。

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值