c语言数据结构(环形队列)

一、什么是队列

  • 队列是一种先进先出的线性表;
  • 可进行插入的一端称为队尾(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;
}
  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值