一、什么是队列
- 队列是一种先进先出的线性表;
- 可进行插入的一端称为队尾(rear),可进行删除的一端称为队首(front);
- 从队列中删除元素称为出队(pop queue),向队列中插入元素称为入队(push queue);
二、环形队列
- 将顺序队列首尾相连就构成了环形队列;
- 环形队列具有固定的元素个数,它使用两个变量分别指向队首和队尾,入队时指向队首变量加一,出队时指向队尾的变量加一,使用队首变量和队尾变量的差值表示队列中实际元素的个数;
- 环形队列的队尾指针指向下一个空闲的元素,队首指针始终指向队列中的第一个有效元素,根据这个特点可以很容易计算出队列中有效数据的长度和剩余空间的长度。
三、队列基本操作
3.1、队列初始化
int RingQueueInit(RingQueue_t *queue)
{
if(NULL == queue)return -1;
queue->front = 0;
queue->rear = 0;
memset(queue->buffer,0,sizeof(queue->buffer));
return 0;
}
3.2、判断队列是否为满
- 当队尾指针加一等于队首指针时,认为队列已满
- 环形对列通常以舍弃一个元素为代价来区分对列满和队列空,也就是说一个长度为n的环形对列,它的实际最大有效空间为n-1。
int IsQueueFull(RingQueue_t *queue)
{
if(NULL == queue)return -1;
if((queue->rear+1)%MAX_QUEUE_LEN == queue->front)
return QUEUE_FULL;
else
return QUEUE_NOT_FULL;
}
3.3、队列为空
- 当队尾指针等于队首指针时认为队列为空
int IsQueueEmpty(RingQueue_t *queue)
{
if(NULL == queue)return -1;
if(queue->front == queue->rear)
return QUEUE_EMPTY;
else
return QUEUE_NOT_EMPTY;
}
3.4、队列的插入
- 队列从队尾插入,在插入前需要先判断队列是否已经满了;
- 需要注意的是,指向队列首部和尾部的变量都只增不减,因此需要对队列长度做取余操作;
int EnQueue(RingQueue_t *queue,char ch)
{
if(NULL == queue)return -1;
if(QUEUE_FULL == IsQueueFull(queue))return QUEUE_FULL;//插入前先判断队列是否已满
queue->buffer[queue->rear] = ch;
queue->rear = (queue->rear+1)%MAX_QUEUE_LEN;
return 0;
}
3.5、队列的删除
int PopQueue(RingQueue_t *queue,char *ch)
{
if(NULL == queue)return -1;
if(QUEUE_EMPTY == IsQueueEmpty(queue))return QUEUE_EMPTY;
*ch = queue->buffer[queue->front];
queue->front = (queue->front+1)%MAX_QUEUE_LEN;
return 0;
}
3.6、获取对列中有效数据的长度
int QueueLength(RingQueue_t *queue)
{
if(queue->front == queue->rear)
return 0;
else
return (queue->rear - queue->front);
}
3.7、获取对列剩余空间
int QueueFreeSpace(RingQueue_t *queue)
{
if((queue->rear+1)%MAX_QUEUE_LEN == queue->front)
return 0;
else
return (MAX_QUEUE_LEN - (queue->rear - queue->front) -1);
}
四、完整代码
RingQueue.h
#ifndef _RINGQUEUE_H
#define _RINGQUEUE_H
#define MAX_QUEUE_LEN 1024
typedef enum{
QUEUE_FULL = -1,
QUEUE_EMPTY = -2,
QUEUE_NOT_FULL = 1,
QUEUE_NOT_EMPTY = 2,
};
typedef struct _queue{
char buffer[MAX_QUEUE_LEN];
int front;
int rear;
}RingQueue_t;
int RingQueueInit(RingQueue_t *queue);
int IsQueueFull(RingQueue_t *queue);
int IsQueueEmpty(RingQueue_t *queue);
int QueueLength(RingQueue_t *queue);
int EnQueue(RingQueue_t *queue,char ch);
int PopQueue(RingQueue_t *queue,char *ch);
#endif
RingQueue.c
/*
* @Copyright (c) 2020 zBlackShadow
*/
/*
* @Copyright (c) 2020 zBlackShadow
*/
#include <stdio.h>
#include <string.h>
#include "RingQueue.h"
int RingQueueInit(RingQueue_t *queue)
{
if(NULL == queue)return -1;
queue->front = 0;
queue->rear = 0;
memset(queue->buffer,0,sizeof(queue->buffer));
return 0;
}
int IsQueueFull(RingQueue_t *queue)
{
if(NULL == queue)return -1;
if((queue->rear+1)%MAX_QUEUE_LEN == queue->front)
return QUEUE_FULL;
else
return QUEUE_NOT_FULL;
}
int IsQueueEmpty(RingQueue_t *queue)
{
if(NULL == queue)return -1;
if(queue->front == queue->rear)
return QUEUE_EMPTY;
else
return QUEUE_NOT_EMPTY;
}
//获取对列有效数据的长度
int QueueLength(RingQueue_t *queue)
{
if(queue->front == queue->rear)
return 0;
else
return (queue->rear - queue->front);
}
//获取对列的剩余空间
int QueueFreeSpace(RingQueue_t *queue)
{
if((queue->rear+1)%MAX_QUEUE_LEN == queue->front)
return 0;
else
return (MAX_QUEUE_LEN - (queue->rear - queue->front) -1);
}
int EnQueue(RingQueue_t *queue,char ch)
{
if(NULL == queue)return -1;
if(QUEUE_FULL == IsQueueFull(queue))return QUEUE_FULL;
queue->buffer[queue->rear] = ch;
queue->rear = (queue->rear+1)%MAX_QUEUE_LEN;
return 0;
}
int PopQueue(RingQueue_t *queue,char *ch)
{
if(NULL == queue)return -1;
if(QUEUE_EMPTY == IsQueueEmpty(queue))return QUEUE_EMPTY;
*ch = queue->buffer[queue->front];
queue->front = (queue->front+1)%MAX_QUEUE_LEN;
return 0;
}
测试代码:
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "RingQueue.h"
typedef struct{
int flag;
RingQueue_t ring_queue;
}mem_data_t;
/*将对列放在共享内存中,根据传入的argv参数判断启动入队或者出队的进程
*/
int main(int arcv,char *argv[])
{
char path[]=".";
int proj_id = 's';
key_t key;
int shmid = -1;
int pid = -1;
int ret = -1;
int count = 0;
mem_data_t *data;
char buf[1024];
//创建共享内存
key = ftok(path,proj_id);
if(key < 0)
{
perror("key create error\r\n");
return -1;
}
shmid = shmget(key,1,0666|IPC_CREAT);
if(shmid < 0)
{
perror("sem get error\r\n");
return -1;
}
data = shmat(shmid,NULL,0);
if(NULL == data)
{
perror("shmat error\r\n");
return -1;
}
memset(data,0,sizeof(mem_data_t));
RingQueueInit(&data->ring_queue);
if(0 == strncmp(argv[1],"read",4))//出队
{
char ch;
int len = 0;
while(1)
{
if(0 == QueueLength(&data->ring_queue))continue;
printf("queue len:%d\r\n",QueueLength(&data->ring_queue));
while(QUEUE_EMPTY != PopQueue(&data->ring_queue,&ch))
{
printf("%c",ch);
}
sleep(1);
}
}
else
{
char ch;
while(1)//入队
{
printf("write something:\r\n");
fgets(buf,1024,stdin);
for(int k=0;k<strlen(buf);k++)
{
EnQueue(&data->ring_queue,buf[k]);
}
printf("free space:%d\r\n",QueueFreeSpace(&data->ring_queue));
}
}
return 0;
}