数据结构——队列

概述:

队列一种先进先出(FIFO)的数据结构,是一种只能在一端进行插入在另一端进行删除操作的特殊线性表。

队列的应用:

1、排队系统的实现

2、使用循环队列存储网络摄像头的数据帧(图像数据)

队列的具体实现:

1、顺序队列

2、链式队列

顺序队列:

顺序队列可以使用一维数组实现,在顺序队列中有两个指针,一指针front指向队列的队首(数组的第0个元素),一个指针rear指向队列的队尾。(此处可以为指针也可以是下表,便于移动位置即可)

不用进行删除操作,直接移动front指针即可。

1、顺序队列的描述

        在这里我们使用数组和指针其实都可以的,但是因为数组是在栈上申请空间,当数据多的时候占用大量的栈空间。而指针是在堆上申请空间,有个好处就是可以手动申请,不用的时候可以释放掉。

#define QUEUE_INIT_LEN 100
#define QUEUEINCREMENT 10 
typedef struct SqQueue { 
ElemType *base; //存储堆上元素的地址空间的首地址 
uint front; //队首指针 
uint rear; //队尾指针 
}SqQueue;

2、关于顺序队列操作的思考

如果对于顺序列队进行出队操作,队首指针怎么移动?

队首指针往后移动

对于顺序列队进行出队操作后被出队的元素占用的空间怎么处理?

 只能暂时空着 ,等待下次循环使用

如何判断顺序列队是否为满,是否为空呢?

  依据是front==rear,因此会有冲突

如何判断列队是否溢出呢?

 当front为0,rear等于最大长度的时候为真溢出,

当front不为0,rear等于列队的最大长度的时候为假溢出。

因此,循环列队就显得尤为重要了

3、循环列队的概念

列队上的各个元素逻辑上形成一个圆环状。

如何判断循环列队是否为满?

  • 将列队上的一个位置作为空闲位置
  • 假设列队的长度为M,当(rear + 1)%M==font的时候认为列队为满(解释:rear为队尾,加上空闲的一个后除以总长度=队首)

4、循环顺序队列例程

#include <stdio.h>
#include "stdlib.h"

typedef int ElemType ;
typedef unsigned int uint;

#define QUEUE_INIT_LEN 10
#define QUEUEINCREMENT 10
#define TRUE 1
#define FALSE 0
 typedef struct SqQueue {
    ElemType *base; //存储堆上元素的地址空间的首地址,当数组来用
    uint front; //指向队首
    uint rear; //指向队尾
}SqQueue;

/* @brief 初始化一个顺序队列
 * @param len 顺序队列的初始化长度(可以存储的元素的最大个数)
 * @return 返回初始化的顺序队列 *
 */
SqQueue Sqqueue_init(uint len)
{
    //先分配空间
    SqQueue s;
    s.base=(ElemType *)malloc(len*sizeof(ElemType));

    //此时队内为空
    s.front=s.rear=0;

    //返回
    return s;
}


/* @brief 获取顺序队列的长度
 * @param s 顺序队列
 * @return 顺序队列的长度 *
 */
int sqQueue_length(SqQueue s)
{
    return s.rear-s.front;
}

/* @brief 判断顺序列队是否为空
 * @param s 顺序队列
 * @return 为空返回TRUE,不为空返回FALSE
 */
int is_empty(SqQueue s)
{
    if(s.front==s.rear)
        return TRUE;
    else
        FALSE;
}

/* @brief 判断顺序列队是否为满
 * @param s 顺序队列
 * @return 为满返回TRUE,不为满返回FALSE
 */
int is_full(SqQueue s)
{
    if((s.rear+1)%QUEUE_INIT_LEN == s.front)
        return TRUE;
    else
        return FALSE;
}

/* @brief 循环顺序列入队
 * @param s 队列地址(在入队函数的时候需要去修改变量的值,所以要传指针)
 * @param data 需要入队的元素
 * @return 成功返回TRUE,失败返回FALSE
 */
int InSqQueue(SqQueue *s ,ElemType data)
{
    if (NULL == s)//判断一下队列是否为空
        FALSE;
    if (is_full(*s) == TRUE) {
        printf("[%s %d] queue is full....\n", __FUNCTION__, __LINE__);
    }
    s->base[s->rear] = data;
    s->rear=(s->rear+1)%QUEUE_INIT_LEN;
    return TRUE;
}

/* @brief 打印输出顺序列队的元素
 * @param s 顺序队列
 * @return 成功返回TRUE,失败返回FALSE
 */
int printf_sqQueue(SqQueue s)
{
    if(is_empty(s) == TRUE)
    {
        printf("[%s %d] SqQueue is empty\n",__FUNCTION__ ,__LINE__);
        return FALSE;
    }
    int i=s.front;
    while(i!=s.rear)
    {
        printf("%d ",s.base[i]);
        //指向下一个位置
        i=(i+1)%QUEUE_INIT_LEN;
    }
    printf("\n");
    return TRUE;
}

/* @brief 循环顺序列出队
 * @param s 队列地址(在入队函数的时候需要去修改变量的值,所以要传指针)
 * @param data 需要出队的元素
 * @return 成功返回TRUE,失败返回FALSE
 */
int Out_SqQueue(SqQueue *s,ElemType *data)
{
    if(is_empty(*s) == TRUE)
    {
        printf("[%s %d] SqQueue is empty\n",__FUNCTION__ ,__LINE__);
        return FALSE;
    }
    *data = s->base[s->front];
    s->front = (s->front+1)%QUEUE_INIT_LEN;//队首指针往后移动
    return TRUE;
}

void main(void)
{
    SqQueue s;
    s=Sqqueue_init(QUEUE_INIT_LEN);
    /*入队*/
    int i;
    for(i=0;i<5;i++)
        InSqQueue(&s,i);
    printf_sqQueue(s);
    /*出队*/
    ElemType data;
    Out_SqQueue(&s,&data);
    printf("OUT:%d\n",data);
    printf_sqQueue(s);

}

链式队列:

链式队列可以理解为对单项链表的操作,入队就是单项链表的尾插法,出队就是需要销毁第一个数据结点(类似删除链表上第一个数据结点)。

1、链式循环队列例程

#include <stdio.h>
#include <stdlib.h>
#define FALSE 0
#define TRUE 1
/*
 * 链式队列可以理解为对单项链表的操作,入队就是单项链表的尾插法,
 * 出队则需要销毁第一个数据结点(类似删除链表上的第一个数据结点)
 * *///没有必要完全和我的一样,只是一种指导思想,目的实现来实现FIFO(先进先出)即可
typedef int ElemType;
typedef unsigned int uint;

/*
 * @brief 定义链表上的一个结点
 * */
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode;

/*
 * @brief 定义一个结构体描述一个链式队列
 * */
typedef struct LinkQueue
{
    LNode *front;//LNode 类型的指针
    LNode *rear;
}LinkQueue;

/*
 * @brief 初始化一个链式队列
 * @return 代表链式队列的结构体
 * */
LinkQueue queue_init()
{
    //创建一个头结点
    LinkQueue L;
    //当列队为空的时候,队首指针和队尾指针都为NULL
    L.front=L.rear=NULL;
    return L;
}

/*
 * @brief 打印链式队列中的元素
 * @param l 链式队列结构体
 * @return
 * */
void printf_queue(LinkQueue L)
{
    //使用临时指针指向链表上的第一个数据结点(就是头结点的下一个结点)
    LNode *tmp;
    tmp = L.front;

    while (tmp != NULL)
    {
        printf("%d ",tmp->data);
        //让tmp指针指向下一个
        tmp=tmp->next;
    }
    printf("\n");
}

/*
 * @brief 入队
 * @param L 链式队列的指针
 * @param data 需要插入的元素
 * @return 成功返回TRUE,失败返回FALSE
 * */
int IN_queue(LinkQueue *L,ElemType data)
{
    if(L==NULL)
        return FALSE;

    //先创建一个结点
    LNode *p = (LNode *)malloc(sizeof(LNode));
    p->next=NULL;
    p->data=data;

    //判断队列是否为空队列
    if(L->front == NULL)
    {
        L->front = p;
        L->rear = p;

        return TRUE;
    }
    //如果队列不为空那么将rear指向新的结点
    L->rear->next=p;
    L->rear=p;

    return TRUE;
}

/*
 * @brief 出队
 * @param L 链式队列的指针
 * @param data 出队的元素
 * @return 成功返回TRUE,失败返回FALSE
 * */
int Out_queue(LinkQueue *L,ElemType *data)
{
    if(L==NULL||data==NULL)
        return FALSE;
    if(NULL == L->front)
        return FALSE;
    //首先保存链式队列上的第一个结点的值
    *data = L->front->data;
    //使用临时指针执行队首
    LNode *t=L->front;//将指向第一个结点的地址给t后,t就指向了该地址
    //队首指针指向第一个结点(出队后原来列表上的第二个结点变成了新的队首结点)
    L->front = L->front->next;
    //释放原来队首结点的空间
    free(t);
    return TRUE;
}

int main() {
    LinkQueue L;
    L=queue_init();
    //进队
    int i;
    for(i=0;i<5;i++)
        IN_queue(&L,10+i);
    printf_queue(L);
    //出队
    ElemType data;
    Out_queue(&L,&data);
    printf("Out:%d\n",data);
    printf_queue(L);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值